(when (require 'undercover nil t)
  (undercover "lispy.el" "lispy-inline.el"))
(require 'lispy nil t)
(require 'clojure-mode nil t)
(require 'le-python)
(if (version< emacs-version "24.4.1")
    (load-library "cl-indent")
  (require 'cl-indent))
(custom-set-variables
 '(indent-tabs-mode nil))
(setq lisp-indent-function 'common-lisp-indent-function)
(put 'if 'common-lisp-indent-function 2)
(transient-mark-mode 1)

;;* Infrastructure
(defmacro lispy-with (in &rest body)
  (let ((mode 'emacs-lisp-mode)
        (mark-str "~"))
    (when (symbolp in)
      (setq mode
            (intern
             (concat (symbol-name in) "-mode")))
      (setq in (car body))
      (setq body (cdr body))
      (when (eq mode 'clojure-mode)
        (setq mark-str "&")))
    `(let ((temp-buffer (generate-new-buffer " *temp*")))
       (save-window-excursion
         (unwind-protect
              (progn
                (switch-to-buffer temp-buffer)
                (,mode)
                (transient-mark-mode 1)
                (lispy-mode)
                (insert ,in)
                (goto-char (point-min))
                (when (search-forward ,mark-str nil t)
                  (backward-delete-char 1)
                  (set-mark (point)))
                (goto-char (point-max))
                (search-backward "|")
                (delete-char 1)
                (setq current-prefix-arg nil)
                ,@(mapcar (lambda (x)
                            (cond ((equal x '(kbd "C-u"))
                                   `(setq current-prefix-arg (list 4)))
                                  ((or (stringp x)
                                       (and (listp x)
                                            (eq (car x) 'kbd)))
                                   `(lispy-unalias ,x))
                                  (t x))) body)
                (insert "|")
                (when (region-active-p)
                  (exchange-point-and-mark)
                  (insert ,mark-str))
                (buffer-substring-no-properties
                 (point-min)
                 (point-max)))
           (and (buffer-name temp-buffer)
                (kill-buffer temp-buffer))
           (setq last-command nil))))))

(defmacro lispy-with-v (mode-ext in &rest body)
  (declare (indent 2))
  (let ((mode (cdr (assoc mode-ext '((py . python-mode)
                                     (el . emacs-lisp-mode)
                                     (scm . scheme-mode)
                                     (clj . clojure-mode))))))
    `(with-temp-buffer
       (,mode)
       (lispy-mode)
       (insert ,in)
       (when (search-backward "~" nil t)
         (delete-char 1)
         (set-mark (point))
         (goto-char (point-max)))
       (search-backward "|")
       (delete-char 1)
       ,@(mapcar (lambda (x) (if (stringp x) `(lispy-unalias ,x) x)) body))))

(defun lispy-decode-keysequence (str)
  "Decode STR from e.g. \"23ab5c\" to '(23 \"a\" \"b\" 5 \"c\")"
  (let ((table (copy-sequence (syntax-table))))
    (cl-loop for i from ?0 to ?9 do
         (modify-syntax-entry i "." table))
    (cl-loop for i from ? to ? do
         (modify-syntax-entry i "w" table))
    (cl-loop for i in '(? ?\( ?\) ?\[ ?\] ?{ ?} ?\" ?\' ?\ )
       do (modify-syntax-entry i "w" table))
    (cl-mapcan (lambda (x)
                 (let ((y (ignore-errors (read x))))
                   (if (numberp y)
                       (list y)
                     (mapcar #'string x))))
               (with-syntax-table table
                 (split-string str "\\b" t)))))

(ert-deftest lispy-decode-keysequence ()
  (should (equal (lispy-decode-keysequence "23ab50c")
                 '(23 "a" "b" 50 "c")))
  (should (equal (lispy-decode-keysequence "3\C-d")
                 '(3 "")))
  (should (equal (lispy-decode-keysequence "3\C-?")
                 '(3 ""))))

(defun lispy-unalias (seq)
  "Emulate pressing keys decoded from SEQ."
  (if (vectorp seq)
      (lispy--unalias-key seq)
    (let ((lkeys (lispy-decode-keysequence seq))
          key)
      (while (setq key (pop lkeys))
        (if (numberp key)
            (let ((current-prefix-arg (list key)))
              (when lkeys
                (lispy--unalias-key (pop lkeys))))
          (lispy--unalias-key key))))))

(defun lispy--unalias-key (key)
  "Call command that corresponds to KEY.
Insert KEY if there's no command."
  (let ((cmd (cdr (or (assoc 'lispy-mode (minor-mode-key-binding key))
                      (assoc 'lispy-other-mode (minor-mode-key-binding key))))))
    (if (or (and cmd (or (looking-at lispy-left)
                         (lispy-looking-back lispy-right)
                         (looking-at lispy-outline)
                         (looking-at ";;")
                         (region-active-p)
                         (and (bolp) (looking-at ";"))))
            (progn
              (setq cmd (key-binding key))
              (not (cond ((eq cmd 'self-insert-command))
                         ((string-match "^special" (symbol-name cmd)))))))
        (progn
          (setq last-command-event (aref key 0))
          (call-interactively cmd)
          (setq last-command cmd))
      (insert key))))

;;* Tests
(ert-deftest lispy-toggle-threaded-last ()
  (should (string= (lispy-with "|(thread-last (a) (b) (c))"
                               (call-interactively #'lispy-toggle-thread-last))
                   "|(c (b (a)))"))
  (should (string= (lispy-with "|(thread-last (a 1) (b 2) (c 3))"
                               (call-interactively #'lispy-toggle-thread-last))
                   "|(c 3 (b 2 (a 1)))"))
  (should (string= (lispy-with "|(c 3 (b 2 (a 1)))"
                               (call-interactively #'lispy-toggle-thread-last))
                   "|(thread-last (a 1) (b 2) (c 3))"))
  (should (string-match-p
           "|(thread-last (org-element-context)\n +(ts-parse-org-element)\n +(ts-unix)\n +(equal 1443070800.0))"
           (lispy-with "|(equal 1443070800.0\n       (ts-unix\n        (ts-parse-org-element\n         (org-element-context))))"
                       (lispy-toggle-thread-last))))
  (should (string= (lispy-with "|(thread-last (org-element-context)\n  (ts-parse-org-element)\n  (ts-unix)\n  (equal 1443070800.0))"
                               (lispy-toggle-thread-last))
                   "|(equal 1443070800.0\n       (ts-unix\n        (ts-parse-org-element\n         (org-element-context))))")))

(ert-deftest lispy-forward ()
  (should (string= (lispy-with "(|(a) (b) (c))" "]")
                   "((a)| (b) (c))"))
  (should (string= (lispy-with "((|a) (b) (c))" "]")
                   "((a)| (b) (c))"))
  (should (string= (lispy-with "((a) |(b) (c))" "]")
                   "((a) (b)| (c))"))
  (should (string= (lispy-with "(|(a) (b) (c))" "]]")
                   "((a) (b)| (c))"))
  (should (string= (lispy-with "(|(a) (b) (c))" "3]")
                   "((a) (b) (c)|)"))
  (should (string= (lispy-with "(|(a) (b) (c))" "]]]]")
                   "((a) (b) (c))|"))
  (should (string= (lispy-with "(|(a) (b) (c))" "4]")
                   "((a) (b) (c)|)"))
  (should (string= (lispy-with "(|(a) (b) (c))" "40]")
                   "((a) (b) (c)|)"))
  (should (string= (lispy-with "(|(a) (b) (c))"
                               (set-mark (point))
                               "]"
                               (call-interactively 'kill-region))
                   "(~| (b) (c))"))
  (should (string= (lispy-with "(|(a) (b) (c))"
                               (set-mark (point))
                               "2]"
                               (call-interactively 'kill-region))
                   "(~| (c))"))
  (should (lispy-with-v el "(|(a) (b) (c))" (set-mark (point)) "]]]" (region-active-p)))
  (should (not (lispy-with-v el "(a) (b) (c)| " (lispy-forward 1))))
  (should (not (lispy-with-v el "(a) (b) (c)|" (lispy-forward 1))))
  ;; break active region when exiting list
  (should (not (lispy-with-v el "(|(a) (b) (c))" (set-mark (point)) "]]]]" (and mark-active (not deactivate-mark)))))
  (should (lispy-with-v el "(a)| (b)\n" (lispy-forward 2))))

(ert-deftest lispy-backward ()
  (should (string= (lispy-with "(|(a) (b) (c))" "[")
                   "|((a) (b) (c))"))
  (should (string= (lispy-with "((a)|)" "[")
                   "(|(a))"))
  (should (string= (lispy-with "((|a) (b) (c))" "[")
                   "(|(a) (b) (c))"))
  (should (string= (lispy-with "((a) |(b) (c))" "[")
                   "(|(a) (b) (c))"))
  (should (string= (lispy-with "(|(a) (b) (c))" "[[")
                   "|((a) (b) (c))"))
  (should (string= (lispy-with "(|(a) (b) (c))" "3[")
                   "|((a) (b) (c))"))
  (should (string= (lispy-with "((a) (b) (c)|)" "[")
                   "((a) (b) |(c))"))
  (should (string= (lispy-with "((a) (b) (c)|)" "4[")
                   "(|(a) (b) (c))"))
  (should (string= (lispy-with "((a) (b) (c)|)" "40[")
                   "(|(a) (b) (c))"))
  (should (string= (lispy-with "((b)|\"foo\")" "[")
                   "(|(b)\"foo\")"))
  (should (string= (lispy-with "(bar)\n;; (foo baar)|" "[")
                   "|(bar)\n;; (foo baar)"))
  (should (string= (lispy-with "(foo)\n;; (foo bar\n;;      tanf)|" "[")
                   "|(foo)\n;; (foo bar\n;;      tanf)")))

(ert-deftest lispy-right ()
  (should (string= (lispy-with "(|(a) (b) (c))" "l")
                   "((a) (b) (c))|"))
  (should (string= (lispy-with "(|(a) (b) (c))" "ll")
                   "((a) (b) (c))|"))
  (should (string= (lispy-with "(|(a) (b) (c))" (lispy-right 1))
                   "((a) (b) (c))|"))
  (should (string= (lispy-with "(|(a) (b) (c))"
                               (lispy-right 1)
                               (lispy-right 1))
                   "((a) (b) (c))|"))
  (should (string= (lispy-with "((|a) (b) (c))" (lispy-right 1))
                   "((a)| (b) (c))"))
  (should (string= (lispy-with "((|a) (b) (c))"
                               (lispy-right 1)
                               (lispy-right 1))
                   "((a) (b) (c))|"))
  (should (string= (lispy-with "((|a) (b) (c))" (lispy-right 2))
                   "((a) (b) (c))|"))
  (should (string= (lispy-with "((a) \"(|foo)\" (c))" (lispy-right 2))
                   "((a) \"(foo)\" (c))|"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something)|)))" "l")
                   "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something))|))"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something)|)))" "ll")
                   "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something)))|)"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something)|)))" "3l")
                   "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something))))|"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something)|)))" "9l")
                   "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something))))|"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      |(something))))" "l")
                   "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something))|))"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      |(something))))" "ll")
                   "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something)))|)"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      |(something))))" "3l")
                   "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something))))|"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      |(something))))" "9l")
                   "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something))))|"))
  (should (string= (lispy-with "|(foo)~" "l")
                   "~(foo)|"))
  (should (string= (lispy-with "~(foo)|" "l")
                   "~(foo)|"))
  (should (string= (lispy-with "(|asdf ?\\ )"
                               (lispy-right 1))
                   "(asdf ?\\ )|")))

(ert-deftest lispy-move-right ()
  (should (string= (lispy-with "(defn |exclaim~ [exclamation]\n  (str exclamation \"!\"))" "col")
                   "(defn exclaim [exclamation]\n  (str exclamation \"!\"))\n|exclaim~"))
  (should (string-match-p "(defn read-resource\n  \"Read a resource into a string.\"\n  \\[path\\]\n  |(-> path\n +clojure.java.io/resource\n +slurp\n +read-string))"
                          (lispy-with "|(defn read-resource\n  \"Read a resource into a string.\"\n  [path]\n  (read-string\n   (slurp\n    (clojure.java.io/resource path))))"
                                      "fffolfol2mol(2 ->[wd>w>w>fdkk///")))
  (should (string= (lispy-with "(progn\n\n  |(sexp1)\n  (sexp2))" "ol")
                   "(progn\n\n  (sexp2))\n|(sexp1)")))

(ert-deftest lispy-dedent-adjust-parens ()
  ;; test reverse of lispy-up-slurp on line with only closing parens
  (should (string= (lispy-with "(let ((a (1+\n          |))))"
                               (lispy-dedent-adjust-parens 1))
                   "(let ((a (1+)\n        |)))"))
  (should (string= (lispy-with "(let ((a (1+)\n        |)))"
                               (lispy-dedent-adjust-parens 1))
                   "(let ((a (1+))\n      |))"))
  (should (string= (lispy-with "(let ((a (1+))\n      |))"
                               (lispy-dedent-adjust-parens 1))
                   "(let ((a (1+)))\n  |)"))
  (should (string= (lispy-with "(let ((a (1+)))\n  |)"
                               (lispy-dedent-adjust-parens 1))
                   "(let ((a (1+))))\n|"))
  (should (string= (lispy-with "(a\n ;; comment\n |)"
                               (lispy-dedent-adjust-parens 1))
                   "(a\n ;; comment\n )\n|"))
  ;; test when in a list with sexps after the current one
  (should (string= (lispy-with "(((a)\n  |(b)\n  (c)\n  (d)))"
                               (lispy-dedent-adjust-parens 1))
                   "(((a))\n |(b)\n (c)\n (d))"))
  (should (string= (lispy-with "(((a))\n |(b)\n (c)\n (d))"
                               (lispy-dedent-adjust-parens 1))
                   "(((a)))\n|(b)\n(c)\n(d)"))
  ;; behave the same even if whitespace after point
  (should (string= (lispy-with "(a\n| )" (lispy-dedent-adjust-parens 1))
                   "(a)\n|"))
  ;; test counts
  (should (string= (lispy-with "(let ((a (1+\n          |))))"
                               (lispy-dedent-adjust-parens 3))
                   "(let ((a (1+)))\n  |)"))
  (should (string= (lispy-with "(let ((a (1+\n          |))))"
                               (lispy-dedent-adjust-parens 20))
                   "(let ((a (1+))))\n|"))
  (should (string= (lispy-with "(((a)\n  |(b)\n  (c)\n  (d)))"
                               (lispy-dedent-adjust-parens 2))
                   "(((a)))\n|(b)\n(c)\n(d)"))
  (should (string= (lispy-with "(\n|a)"
                               (lispy-dedent-adjust-parens 1))
                   "()\n|a"))
  (should (string= (lispy-with "((a\n  ;; comment\n  |))"
                               (lispy-dedent-adjust-parens 2))
                   "((a\n  ;; comment\n  ))\n|")))

(ert-deftest lispy-move-left ()
  (should (string= (lispy-with "(progn\n |(sexp1)\n (sexp2))" "oh")
                   "|(sexp1)\n(progn\n  (sexp2))")))

(ert-deftest lispy-down-slurp ()
  (should (string= (lispy-with "(progn\n\n  |(sexp1)\n  (sexp2))" "oj")
                   "(progn\n\n  (|(sexp1)\n   sexp2))"))
  (should (string= (lispy-with "|(fee) (fi) [fo]" "oj")
                   "(|(fee)\n fi) [fo]"))
  (should (string= (lispy-with "(fee) |(fi) [fo]" "oj")
                   "(fee) [|(fi)\n       fo]")))

(ert-deftest lispy-left ()
  (should (string= (lispy-with "(|(a) (b) (c))" "h")
                   "|((a) (b) (c))"))
  (should (string= (lispy-with "(|(a) (b) (c))" "hh")
                   "|((a) (b) (c))"))
  (should (string= (lispy-with "((a)| (b) (c))" "h")
                   "|((a) (b) (c))"))
  (should (string= (lispy-with "((a) (b)| (c))" "h")
                   "|((a) (b) (c))"))
  (should (string= (lispy-with "((a) |(b) (c))" "h")
                   "|((a) (b) (c))"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something)|)))" "h")
                   "(defun foo ()\n  (let ((a 1))\n    |(let ((b 2))\n      (something))))"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something)|)))" "hh")
                   "(defun foo ()\n  |(let ((a 1))\n    (let ((b 2))\n      (something))))"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something)|)))" "3h")
                   "|(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something))))"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something)|)))" "9h")
                   "|(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something))))"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      |(something))))" "h")
                   "(defun foo ()\n  (let ((a 1))\n    |(let ((b 2))\n      (something))))"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      |(something))))" "hh")
                   "(defun foo ()\n  |(let ((a 1))\n    (let ((b 2))\n      (something))))"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      |(something))))" "3h")
                   "|(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something))))"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      |(something))))" "9h")
                   "|(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something))))"))
  (should (equal (lispy-with-v el "|(foo)" (lispy-backward 1)) nil))
  (should (equal (lispy-with "((foo \"(\"))\n((foo \")\"))\n\"un|expected\"" (lispy-backward 1))
                 "((foo \"(\"))\n|((foo \")\"))\n\"unexpected\""))
  (should (equal (lispy-with "(defun charge! ()\n|(run-away))" "h")
                 "|(defun charge! ()\n  (run-away))"))
  (should (string= (lispy-with "|(foo)~" "h")
                   "|(foo)~"))
  (should (string= (lispy-with "~(foo)|" "h")
                   "|(foo)~")))

(ert-deftest lispy-flow ()
  (should (string= (lispy-with "(|(a) (b) (c))" "f")
                   "((a) |(b) (c))"))
  (should (string= (lispy-with "(|(a) (b) (c))" "ff")
                   "((a) (b) |(c))"))
  (should (string= (lispy-with "((a)| (b) (c))" "f")
                   "((a)| (b) (c))"))
  (should (string= (lispy-with "((a) (b)| (c))" "f")
                   "((a)| (b) (c))"))
  (should (string= (lispy-with "((a) |(b) (c))" "f")
                   "((a) (b) |(c))"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something)|)))" "f")
                   "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))|\n      (something))))"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something)|)))" "ff")
                   "(defun foo ()\n  (let ((a 1))\n    (let ((b 2)|)\n      (something))))"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something)|)))" "3f")
                   "(defun foo ()\n  (let ((a 1))|\n    (let ((b 2))\n      (something))))"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      (something)|)))" "9f")
                   "(defun foo ()|\n  (let ((a 1))\n    (let ((b 2))\n      (something))))"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      |(something))))" "f")
                   "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      |(something))))"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      |(something))))" "ff")
                   "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      |(something))))"))
  (should (string= (lispy-with "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      |(something))))" "3f")
                   "(defun foo ()\n  (let ((a 1))\n    (let ((b 2))\n      |(something))))"))
  (should (string= (lispy-with "|;; herp\n;; (foo)\n;; \n(derp)" "f")
                   ";; herp\n;; (foo)\n;; \n|(derp)")))

(ert-deftest lispy-down ()
  (should (string= (lispy-with "(|(a) (b) (c))" "j")
                   "((a) |(b) (c))"))
  (should (string= (lispy-with "(|(a) (b) (c))" "jj")
                   "((a) (b) |(c))"))
  (should (string= (lispy-with "(|(a) (b) (c))" "2j")
                   "((a) (b) |(c))"))
  (should (string= (lispy-with "(|(a) (b) (c))" "jjj")
                   "((a) (b) |(c))"))
  (should (string= (lispy-with "(|(a) (b) (c))" "3j")
                   "((a) (b) |(c))"))
  (should (string= (lispy-with "(|(a) (b) (c))" "jjjj")
                   "((a) (b) |(c))"))
  (should (string= (lispy-with "(|(a) (b) (c))" "4j")
                   "((a) (b) |(c))"))
  (should (string= (lispy-with "(a)| (b)\n" "2j")
                   "(a) (b)|\n"))
  (should (string= (lispy-with "(foo\n |(one)\n two\n (three)\n (four))" "j")
                   "(foo\n (one)\n two\n |(three)\n (four))"))
  (should (string= (lispy-with "(foo\n |(one)\n two\n (three)\n (four))" "jj")
                   "(foo\n (one)\n two\n (three)\n |(four))"))
  (should (string= (lispy-with "(foo\n |(one)\n two\n (three)\n (four))" "jjj")
                   "(foo\n (one)\n two\n (three)\n |(four))"))
  (should (string= (lispy-with "(foo\n (one)|\n two\n (three)\n (four))" "j")
                   "(foo\n (one)\n two\n (three)|\n (four))"))
  (should (string= (lispy-with "(foo\n (one)|\n two\n (three)\n (four))" "jj")
                   "(foo\n (one)\n two\n (three)\n (four)|)"))
  (should (string= (lispy-with "(foo\n (one)|\n two\n (three)\n (four))" "jjj")
                   "(foo\n (one)\n two\n (three)\n (four)|)"))
  (should (string= (lispy-with "(progn\n  |foo-bar~-baz-flip-flop)" (lispy-down 1))
                   "(progn\n  foo-|bar-baz~-flip-flop)"))
  (should (string= (lispy-with "(progn\n  |foo-bar~-baz-flip-flop)" (lispy-down 5))
                   "(progn\n  foo-bar-baz-|flip-flop~)"))
  (should (string= (lispy-with "(progn\n  ~foo-bar|-baz-flip-flop)" (lispy-down 1))
                   "(progn\n  foo-~bar-baz|-flip-flop)"))
  (should (string= (lispy-with "(progn\n  ~foo-bar|-baz-flip-flop)" (lispy-down 5))
                   "(progn\n  foo-bar-baz-~flip-flop|)"))
  (should (string= (lispy-with "(eval-when-~compile|\n  (require 'cl))" (lispy-down 1))
                   "(eval-when-~compile|\n  (require 'cl))"))
  (should (string= (lispy-with "~;; foo|\n(bar)" (lispy-down 1))
                   ";; foo\n~(bar)|"))
  (should (string= (lispy-with "~(foo)|\n;; comment\n(bar)" "j")
                   "(foo)\n~;; comment|\n(bar)"))
  (should (string= (lispy-with "~(foo)|\n;; comment\n(bar)" "jj")
                   "(foo)\n;; comment\n~(bar)|")))

(ert-deftest lispy-up ()
  (should (string= (lispy-with "((a) (b) (c)|)" "k")
                   "((a) (b)| (c))"))
  (should (string= (lispy-with "((a) (b) (c)|)" "kk")
                   "((a)| (b) (c))"))
  (should (string= (lispy-with "((a) (b) (c)|)" "2k")
                   "((a)| (b) (c))"))
  (should (string= (lispy-with "((a) (b) (c)|)" "kkk")
                   "((a)| (b) (c))"))
  (should (string= (lispy-with "((a) (b) (c)|)" "3k")
                   "((a)| (b) (c))"))
  (should (string= (lispy-with "((a) (b) (c)|)" "kkkk")
                   "((a)| (b) (c))"))
  (should (string= (lispy-with "((a) (b) (c)|)" "4k")
                   "((a)| (b) (c))"))
  (should (string= (lispy-with ";; \n(foo)\n|(bar)" "2k")
                   ";; \n|(foo)\n(bar)"))
  (should (string= (lispy-with "(foo\n |(one)\n two\n (three)\n (four))" "k")
                   "(foo\n |(one)\n two\n (three)\n (four))"))
  (should (string= (lispy-with "(foo\n |(one)\n two\n (three)\n (four))" "kk")
                   "(foo\n |(one)\n two\n (three)\n (four))"))
  (should (string= (lispy-with "(foo\n (one)|\n two\n (three)\n (four))" "k")
                   "(foo\n (one)|\n two\n (three)\n (four))"))
  (should (string= (lispy-with "(foo\n (one)\n two\n (three)|\n (four))" "k")
                   "(foo\n (one)|\n two\n (three)\n (four))"))
  (should (string= (lispy-with "(foo\n (one)\n two\n (three)|\n (four))" "kk")
                   "(foo\n (one)|\n two\n (three)\n (four))"))
  (should (string= (lispy-with "(foo\n (one)\n two\n (three)\n (four)|)" "k")
                   "(foo\n (one)\n two\n (three)|\n (four))"))
  (should (string= (lispy-with "(foo\n (one)\n two\n (three)\n (four)|)" "kk")
                   "(foo\n (one)|\n two\n (three)\n (four))"))
  (should (string= (lispy-with "(foo\n (one)\n two\n (three)\n (four)|)" "kk")
                   "(foo\n (one)|\n two\n (three)\n (four))"))
  (should (string= (lispy-with "(progn\n  foo-bar-baz-~flip-flop|)" (lispy-up 1))
                   "(progn\n  foo-bar-~baz-flip|-flop)"))
  (should (string= (lispy-with "(progn\n  foo-bar-baz-~flip-flop|)" (lispy-up 5))
                   "(progn\n  ~foo-bar|-baz-flip-flop)"))
  (should (string= (lispy-with "(progn\n  foo-bar-baz-|flip-flop~)" (lispy-up 1))
                   "(progn\n  foo-bar-|baz-flip~-flop)"))
  (should (string= (lispy-with "(progn\n  foo-bar-baz-|flip-flop~)" (lispy-up 5))
                   "(progn\n  |foo-bar~-baz-flip-flop)"))
  (should (string= (lispy-with "(foo)\n;; comment\n~(bar)|" "k")
                   "(foo)\n~;; comment|\n(bar)"))
  (should (string= (lispy-with "(foo)\n;; comment\n~(bar)|" "kk")
                   "~(foo)|\n;; comment\n(bar)"))
  (should (string= (lispy-with "(foo)\n;; comment\n|(bar)~" "k")
                   "(foo)\n|;; comment~\n(bar)"))
  (should (string= (lispy-with "(foo)\n;; comment\n|(bar)~" "kk")
                   "|(foo)~\n;; comment\n(bar)"))
  (should (string= (lispy-with "(~foo| bar)" "k")
                   "(~foo| bar)")))

(ert-deftest lispy-different ()
  (should (string= (lispy-with "((a) (b) (c)|)" "d")
                   "((a) (b) |(c))"))
  (should (string= (lispy-with "((a) (b) (c)|)" "dd")
                   "((a) (b) (c)|)"))
  (should (string= (lispy-with "((a) (b) (c))|" "d")
                   "|((a) (b) (c))")))

(ert-deftest lispy-kill ()
  (should (string= (lispy-with "\n\n|(defun foo ()\n    )" (lispy-kill))
                   "\n\n|"))
  ;; while ahead of defun, and there's a comment before, move there
  (should (string= (lispy-with "\n;comment\n|(defun foo ()\n    )" (lispy-kill))
                   "\n;comment\n|"))
  (should (string= (lispy-with "(|(a) (b) (c))" "\C-k")
                   "(|)"))
  (should (string= (lispy-with "((a)\n| (b)\n (c))" "\C-k")
                   "((a)\n|\n (c))"))
  (should (string= (lispy-with "((a) |(b) (c))" "\C-k")
                   "((a) |)"))
  (should (string= (lispy-with "((a) (b) |(c))" "\C-k")
                   "((a) (b) |)"))
  (should (string= (lispy-with "((a)|\n (b) (c))" "\C-k")
                   "((a)| (b) (c))"))
  (should (string= (lispy-with "((a)|\n (b) (c))" "\C-k\C-k")
                   "((a)|)"))
  (should (string= (lispy-with "(a b c)\n(|)" "\C-k")
                   "(a b c)\n|"))
  (should (string= (lispy-with "(foo\nbar | baz  )" "\C-k")
                   "(foo\nbar |)"))
  (should (string= (lispy-with "[1 |2 3]" "\C-k")
                   "[1 |]"))
  (should (string= (lispy-with "(looking-at |\"foo\")" "\C-k")
                   "(looking-at |)"))
  (should (string= (lispy-with "(looking-at |\"foo\" (bar))" "\C-k")
                   "(looking-at |)"))
  (should (string= (lispy-with "(list |\"foo\"\n      (bar))" "\C-k")
                   "(list |\n      (bar))"))
  (should (string= (lispy-with "(looking-at \"|;\")" "\C-k")
                   "(looking-at \"|\")"))
  (should (string= (lispy-with "(foo)|   ;bar\n(baz)" "\C-k")
                   "(foo)|\n(baz)"))
  (should (string= (lispy-with "|#[foo\n  bar]" "\C-k")
                   "|"))
  (should (string= (lispy-with "|#(foo\n  bar)" "\C-k")
                   "|"))
  (should (string= (lispy-with clojure "{:a 1 |:b 2}" "\C-k")
                   "{:a 1 |}"))
  (should (string= (lispy-with "|\"multiline\nstring\"\n(expr)" "\C-k")
                   "|\n(expr)"))
  (should (string= (lispy-with "(defun lispy-kill-test ()\n  |(foo\n    bar baz)\n  (1 2 3)\n  (a b c))" "\C-k")
                   "(defun lispy-kill-test ()\n  |\n  (1 2 3)\n  (a b c))"))
  (should (string= (lispy-with "(defun test ()\n  |(foo)) ;; comment" "\C-k")
                   "(defun test ()\n  |) ;; comment"))
  (should (string= (lispy-with "(progn\n  |(looking-at-p \"\\(\"))" "\C-k")
                   "(progn\n  |)"))
  (should (string= (lispy-with "(progn\n|  ;;  Comment\n  (new-code))" "\C-k")
                   "(progn\n|\n  (new-code))"))
  (should (equal (lispy-with "(progn\n  |\"test\" \n  (bar))"
                             "\C-k")
                 "(progn\n  |\n  (bar))"))
  (should (equal (lispy-with "(progn\n|  \"docs\" ;;  0\n  (one)  ;;  1\n  )"
                             "\C-k")
                 "(progn\n|\n  (one)  ;;  1\n  )")))

(ert-deftest lispy-yank ()
  (should (string= (lispy-with "\"|\"" (kill-new "foo") (lispy-yank))
                   "\"foo|\""))
  (should (string= (lispy-with "\"|\"" (kill-new "\"foo\"") (lispy-yank))
                   "\"\\\"foo\\\"|\""))
  (let ((lispy-safe-paste t)
        (lispy-safe-actions-no-pull-delimiters-into-comments t))
    (should (string= (lispy-with "\"|\"" (kill-new "{([\"a\"") (lispy-yank))
                     "\"{([\\\"a\\\"])}|\""))
    (should (string= (lispy-with "\"|\"" (kill-new "\"a\")}]") (lispy-yank))
                     "\"[{(\\\"a\\\")}]|\""))
    (should (string= (lispy-with "\"|\"" (kill-new "\"a\")]} ({[\"b\"")
                                 (lispy-yank))
                     "\"{[(\\\"a\\\")]} ({[\\\"b\\\"]})|\""))
    (should (string= (lispy-with "|" (kill-new "(a\n;;foo") (lispy-yank))
                     "(a\n;;foo\n)|"))))

(ert-deftest lispy-delete ()
  (should (string= (lispy-with "(|(a) (b) (c))" "\C-d")
                   "(|(b) (c))"))
  (should (string= (lispy-with "(|(a) (b) (c))" "2\C-d")
                   "(|(c))"))
  (should (string= (lispy-with "(|(a) (b) (c))" "3\C-d")
                   "(|)"))
  (should (string= (lispy-with "(|(a) (b) (c))" "3\C-d\C-d")
                   "|()"))
  (should (string= (lispy-with "(|(a) \"foo\")" "\C-d")
                   "(|\"foo\")"))
  (should (string= (lispy-with "(|(a)\"foo\")" "\C-d")
                   "(|\"foo\")"))
  (should (string= (lispy-with "(|(a) b (c))" "\C-d")
                   "(|b (c))"))
  (should (string= (lispy-with "((a) |\"foo\" (c))" "\C-d")
                   "((a) |(c))"))
  (should (string= (lispy-with "((a) (|) (c))" "\C-d")
                   "((a) |() (c))"))
  (should (string= (lispy-with "(a (|) c)" "\C-d")
                   "(a |() c)"))
  (should (string= (lispy-with "(foo \"bar|\")" "\C-d")
                   "(foo |\"bar\")"))
  (should (string= (lispy-with "\"foo|\\\"\\\"\"" "\C-d")
                   "\"foo|\\\"\""))
  (should (string= (lispy-with "\"|\\\\(foo\\\\)\"" "\C-d")
                   "\"|foo\""))
  (should (string= (lispy-with "\"\\\\(foo|\\\\)\"" "\C-d")
                   "\"foo|\""))
  (should (string= (lispy-with "(looking-at \"\\\\([a-z]+|\\\\)\")" "\C-d")
                   "(looking-at \"[a-z]+|\")"))
  (should (string= (lispy-with "(progn `|(foobar) (foo))" "\C-d")
                   "(progn |(foo))"))
  (should (string= (lispy-with "(require 'foo)\n\n|(require 'bar)\n\n(require 'baz)" "\C-d")
                   "(require 'foo)\n\n|(require 'baz)"))
  (should (string= (lispy-with "|\n(foo)" "\C-d")
                   "|(foo)"))
  (should (string= (lispy-with "\"\\|\"\"" "\C-d")
                   "\"|\""))
  (should (string= (lispy-with "|(require 'foo)\n\n;; comment" "\C-d")
                   "|\n\n;; comment"))
  (should (string= (lispy-with "(progn\n  |;; a comment\n  (test))" "\C-d")
                   "(progn\n  |\n  (test))"))
  (should (string= (lispy-with "|;; a comment\n(test))" "\C-d")
                   "|\n(test))"))
  (should (string= (lispy-with "(defun foobar |()   \n  (this-and-that))" "\C-d")
                   "(defun foobar |\n  (this-and-that))"))
  (should (string= (lispy-with "(defun foobar |\n  (this-and-that))" "\C-d")
                   "(defun foobar |(this-and-that))"))
  (should (string= (lispy-with "((a) |\"foo\" (c))"
                               (lispy-delete -1))
                   "(|\"foo\" (c))"))
  (should (string= (lispy-with "(a)'|(b)" "\C-d") "(a)|"))
  ;; test that quotes also get deleted
  (should (string= (lispy-with "'|()" "\C-d")
                   "|"))
  (should (string= (lispy-with "(,@|())" "\C-d")
                   "(|)"))
  (should (string= (lispy-with "#2A|((a b) (0 1))" "\C-d")
                   "|"))
  (let ((lispy-safe-delete t))
    ;; region is already safe
    (should (string= (lispy-with "((a) ~(b (c (d)))|)" "\C-d")
                     "((a) ~|)"))
    ;; region cannot be made safe
    (should (string= (lispy-with "~(|a)" "\C-d")
                     "~(|a)"))
    ;; region can be safely dealt with
    (should (string= (lispy-with "(~a) |" "\C-d")
                     "(~)|"))
    (should (string= (lispy-with "~ (a|)" "\C-d")
                     "~(|)"))
    (should (string= (lispy-with "(a ~((b)|))" "\C-d")
                     "(a ~(|))"))
    (should (string= (lispy-with "(a~ b)\n(c |d)" "\C-d")
                     "(a~)(|d)"))
    (should (string= (lispy-with "(a~ b) (c d) (e |f)" "\C-d")
                     "(a~)(|f)"))
    (should (string= (lispy-with "((((a ~b))))\n ((((c| d))))" "\C-d")
                     "((((a ~))))((((| d))))"))
    (should (string= (lispy-with "(((a\n ~(b c))))|" "\C-d")
                     "(((a\n ~)))|"))
    (should (string= (lispy-with "~((((a b)|\n c)))" "\C-d")
                     "~(((|\n c)))"))
    (should (string= (lispy-with "(((a\n ~(b c)\n d)|))" "\C-d")
                     "(((a\n ~)|))"))
    (should (string= (lispy-with "((~(a\n (b c)|\n d)))" "\C-d")
                     "((~(|\n d)))"))
    ;; strings
    (should (string= (lispy-with "~\"I am your |king.\"" "\C-d")
                     "~\"|king.\""))
    (should (string= (lispy-with "\"elder~berries\" \"a |witch\"" "\C-d")
                     "\"elder~\"\"|witch\""))
    (should (string= (lispy-with "~(1 (2 (3 \"a |duck\")))" "\C-d")
                     "~(((\"|duck\")))"))
    (should (string= (lispy-with "(((\"a ~duck\" 3) 2) 1)|" "\C-d")
                     "(((\"a ~\")))|"))
    ;; test ignoring delimiters in strings
    (should (string= (lispy-with "\"~( is a left paren.|\"" "\C-d")
                     "\"~|\""))
    (should (string= (lispy-with "~a \"([[{b |c\"" "\C-d")
                     "~\"|c\""))
    (should (string= (lispy-with "\"a ~b)]}\" c|" "\C-d")
                     "\"a ~\"|"))
    (should (string= (lispy-with "~a \"(b {c]\" d|" "\C-d")
                     "~|"))
    (should (string= (lispy-with "a \"~(\"\"]\" \"((|)\" b" "\C-d")
                     "a \"~\"\"|)\" b"))
    ;; test that a right quote at end of the region is not deleted
    (should (string= (lispy-with "\"a ~string\"|" "\C-d")
                     "\"a ~\"|"))
    ;; mixed
    (should (string= (lispy-with "~{[(a b \"(c|\" d)]}" "\C-d")
                     "~{[(\"|\" d)]}"))
    ;; test ignoring delimiters in comments
    (should (string= (lispy-with "~;; ([[{{|" "\C-d")
                     "~|"))
    (should (string= (lispy-with ";; ~([[{{\n a|" "\C-d")
                     ";; ~|"))
    (should (string= (lispy-with "~{[(a\n b\n ;; ]{](\n| d)]}" "\C-d")
                     "~{[(| d)]}"))
    (should (string= (lispy-with "{[(a~\n b\n ;; ]{](\n d)]}|" "\C-d")
                     "{[(a~)]}|"))
    ;; delimiters before comments shouldn't be considered part of the comment
    (should (string= (lispy-with "~(;; a\n |b)" "\C-d")
                     "~(|b)"))
    ;; both mixed
    (should (string= (lispy-with "{[(a\n~   b \"c [(d e}\"\n   ;;({]\n|   f)]}"
                                 "\C-d")
                     "{[(a\n~|   f)]}"))
    (let ((lispy-safe-actions-no-pull-delimiters-into-comments t))
      (should (string= (lispy-with "(a\n;; foo~bar\n|b)" "\C-d")
                       "(a\n;; foo~\n|b)"))
      (should (string= (lispy-with "(a\n;; foo~bar\nb|)" "\C-d")
                       "(a\n;; foo~\n|)"))
      (should (string= (lispy-with "(a\n;; foo~bar\nb)|" "\C-d")
                       "(a\n;; foo~\n)|"))
      ;; test that full comments are deleted with their newlines
      (should (string= (lispy-with ";; foo\n~;;bar\n|(baz)" "\C-d")
                       ";; foo\n~|(baz)"))
      (should (string= (lispy-with ";; foo\n~;;bar\n|(baz\n qux)" "\C-d")
                       ";; foo\n~|(baz\n qux)"))))

  (let ((lispy-delete-sexp-from-within t))
    (should (string= (lispy-with "(|)" "\C-d") "|"))
    (should (string= (lispy-with "(foo|)" "\C-d") "|"))
    (should (string= (lispy-with "\"|\"" "\C-d") "|"))
    (should (string= (lispy-with "\"foo|\"" "\C-d") "|"))))

(ert-deftest lispy-delete-backward ()
  (should (string= (lispy-with "((a) (b) (c)|)" "\C-?")
                   "((a) (b)|)"))
  (should (string= (lispy-with "(list)(foo)|" "\C-?")
                   "(list)|"))
  (should (string= (lispy-with "((a) (b) (c)|)" "2\C-?")
                   "((a)|)"))
  (should (string= (lispy-with "((a) (b) (c)|)" "3\C-?")
                   "(|)"))
  (should (string= (lispy-with "(a (b)| c)" "\C-?")
                   "(a| c)"))
  (should (string= (lispy-with "(a (|) c)" "\C-?")
                   "(a| c)"))
  (should (string= (lispy-with "(foo \"|bar\")" "\C-?")
                   "(foo \"bar\"|)"))
  (should (string= (lispy-with "(a \"\"| c)" "\C-?")
                   "(a| c)"))
  (should (string= (lispy-with "(a        \"\"| c)" "\C-?")
                   "(a| c)"))
  (should (string= (lispy-with ";|" "\C-?")
                   "|"))
  (should (string= (lispy-with "\"\\\\(|foo\\\\)\"" "\C-?")
                   "\"|foo\""))
  (should (string= (lispy-with "\"\\\\(foo\\\\)|\"" "\C-?")
                   "\"foo|\""))
  (should (string= (lispy-with "\"\\\\(|foo\"" "\C-?")
                   "\"\\\\|foo\""))
  (should (string= (lispy-with "(foo)\n;; ()|" "\C-?")
                   "(foo)\n;; (|"))
  (should (string= (lispy-with "(~\"foo\"|)" "\C-?")
                   "(~|)"))
  (should (string= (lispy-with "(|\"foo\"~)" "\C-?")
                   "(~|)"))
  (should (string= (lispy-with "(foo bar)\n;; comment\n(foo bar)|" "\C-?")
                   "(foo bar)\n;; comment\n|"))
  (should (string= (lispy-with "(require 'foo)\n\n(require 'bar)|\n\n(require 'baz)" "\C-?")
                   "(require 'foo)\n\n|\n\n(require 'baz)"))
  (should (string= (lispy-with "(list\n (foo)\n |(bar))" "\C-?")
                   "(list\n (foo) |(bar))"))
  (should (string= (lispy-with "(list\n (foo)\n |\"bar\")" "\C-?")
                   "(list\n (foo) |\"bar\")"))
  (should (string= (lispy-with "   |(foo)" "\C-?")
                   "|(foo)"))
  (should (string= (lispy-with "(foo (bar) |)" "\C-?")
                   "(foo (bar)|)"))
  (should (string= (lispy-with "(bar)\n;; bar\n|(baz)" "\C-?")
                   "(bar)\n|(baz)"))
  (should (string= (lispy-with "(bar)\n;; bar\n   |(baz)" "\C-?")
                   "(bar)\n|(baz)"))
  (should (string= (lispy-with "(\n |(a))" "\C-?")
                   "(|(a))"))
  (should (string= (lispy-with "(list (foo) |(bar))" "\C-?")
                   "(list |(bar))"))
  (should (string= (lispy-with "(list (foo) |\"bar\")" "\C-?")
                   "(list |\"bar\")"))
  (should (string= (lispy-with "\"We want...\"         |\"a shrubbery!\"" "\C-?")
                   "\"We want...\" |\"a shrubbery!\""))
  (should (string= (lispy-with "\"\\C|-j\"" "\C-?")
                   "\"|-j\""))
  (should (string= (lispy-with "(progn\n  (foo)\n\n  |;; upcoming magic\n  (magic))" "\C-?")
                   "(progn\n  (foo)\n  |;; upcoming magic\n  (magic))"))
  (should (string= (lispy-with "(list \"foo\" |)" "\C-?")
                   "(list \"foo\"|)"))
  (should (string= (lispy-with "\"a\\n|\"" "\C-?")
                   "\"a|\""))
  (should (string= (lispy-with "\"\\\\n|\"" "\C-?")
                   "\"\\\\|\""))
  (should (string= (lispy-with "((a) |(b) (c))"
                               (lispy-delete-backward -1))
                   "((a) |(c))"))
  (should (string= (lispy-with ";; foo\n|\n(bar)" "\C-?")
                   ";; foo|\n(bar)"))
  (should (string= (lispy-with "(foo ?{|)" "\C-?")
                   "(foo ?|)"))
  (should (string= (lispy-with "(foo ?}|)" "\C-?")
                   "(foo ?|)"))
  (should (string= (lispy-with "(list \"string\" |[1 2])" "\C-?")
                   "(list |[1 2])"))
  (should (string= (lispy-with "#2A((a b) (0 1))|" "\C-?")
                   "|"))
  (should (string= (lispy-with clojure "(partial filter neg?)|" "\C-?")
                   "|"))
  (let ((lispy-delete-sexp-from-within t))
    (should (string= (lispy-with "(|)" "\C-?") "|"))
    (should (string= (lispy-with "(|foo)" "\C-?") "|"))
    (should (string= (lispy-with "\"|\"" "\C-?") "|"))
    (should (string= (lispy-with "\"|foo\"" "\C-?") "|")))

  (should (string= (lispy-with "(foo                                    ; |\n)" "\C-?")
                   "(foo|)"))
  (should (string= (lispy-with "(foo\n ;; |\n)" "\C-?") "(foo\n |\n)"))
  (should (string= (lispy-with "(foo) ;; |" "\C-?") "(foo)|"))
  (should (string= (lispy-with "(foo ;; |\n)" "\C-?") "(foo|)"))
  (should (string= (lispy-with " |;;" "\C-?")
                   "|;;"))
  (should (string= (lispy-with "  |;;" "\C-?")
                   "|;;"))
  (should (string= (lispy-with clojure "(foo bar?)|" "\C-?") "|")))

(ert-deftest lispy-pair ()
  (should (string= (lispy-with "\"\\\\|\"" "(")
                   "\"\\\\(|\\\\)\""))
  (should (string= (lispy-with "\"\\\\|\"" "{")
                   "\"\\\\{|\\\\}\""))
  (should (string= (lispy-with "\"\\\\|\"" "}")
                   "\"\\\\[|\\\\]\""))
  (should (string= (lispy-with "|foo bar~" "(")
                   "|(foo bar)"))
  (should (string= (lispy-with "~foo bar|" "(")
                   "|(foo bar)"))
  (should (string= (lispy-with "(progn\n|\n (foo))" "1(")
                   "(progn\n  (|\n   (foo)))"))
  (should (string= (lispy-with "a| b c" (kbd "C-u") "(")
                   "(| a) b c"))
  (should (string= (lispy-with "a| b c" (setq current-prefix-arg 1) "(")
                   "(| a) b c"))
  (should (string= (lispy-with "a| b c" (setq current-prefix-arg 2) "(")
                   "(| a b) c"))
  (should (string= (lispy-with "a| b c" (setq current-prefix-arg 3) "(")
                   "(| a b c)"))
  (should (string= (lispy-with "a| b c" (setq current-prefix-arg 0) "(")
                   "(| a b c)"))
  (should (string= (lispy-with "a| b c" (setq current-prefix-arg -1) "(")
                   "(| a b c)"))
  (should (string= (lispy-with "|(a b c)\n(d e f)" (setq current-prefix-arg -1) "(")
                   "(| (a b c))\n(d e f)"))
  (should (string= (lispy-with "|(a b c)\n(d e f)" (setq current-prefix-arg 0) "(")
                   "(| (a b c)\n (d e f))"))
  (should (string= (lispy-with "|" (setq current-prefix-arg -1) "(")
                   "(|)"))
  (should (string= (lispy-with "(|)" (setq current-prefix-arg -1) "(")
                   "((|))"))
  (should (string= (lispy-with "(a |)" (setq current-prefix-arg -1) "(")
                   "(a (|))"))
  (should (string= (lispy-with "(| a)" (setq current-prefix-arg -1) "(")
                   "((| a))"))
  (should (string= (lispy-with "(a | b)" (setq current-prefix-arg -1) "(")
                   "(a (| b))"))
  (should (string= (lispy-with "(a |\n )" (setq current-prefix-arg -1) "(")
                   "(a (|)\n )"))
  (should (string= (lispy-with "(|\n )" (setq current-prefix-arg -1) "(")
                   "((|)\n )"))
  (should (string= (lispy-with "(a\n |)" (setq current-prefix-arg -1) "(")
                   "(a\n (|))"))
  (should (string= (lispy-with "(a '|)" (setq current-prefix-arg -1) "(")
                   "(a '(|))"))
  (should (string= (lispy-with "(a |) " (setq current-prefix-arg -1) "(")
                   "(a (|)) "))
  (let (lispy-insert-space-after-wrap)
    (should (string= (lispy-with "a| b c" (kbd "C-u") "(")
                     "(|a) b c"))))

(ert-deftest lispy--sub-slurp-forward ()
  (should (eq (lispy-with-v el "(progn\n  ~foo|-bar-baz-flip-flop)"
                                (lispy--sub-slurp-forward 1)) 1))
  (should (eq (lispy-with-v el "(progn\n  ~foo|-bar-baz-flip-flop)"
                                (lispy--sub-slurp-forward 4)) 4))
  (should (eq (lispy-with-v el "(progn\n  ~foo|-bar-baz-flip-flop)"
                                (lispy--sub-slurp-forward 5)) 4))
  (should (eq (lispy-with-v el "(progn\n  ~foo|-bar-baz-flip-flop)"
                                (lispy--sub-slurp-forward 10)) 4))
  (should (eq (lispy-with-v el "(progn\n  ~foo|-bar-baz-flip-flop)"
                                (lispy--sub-slurp-forward 5)
                                (lispy--sub-slurp-forward 1)) nil)))

(ert-deftest lispy--sub-slurp-backward ()
  (should (eq (lispy-with-v el "(progn\n  foo-bar-baz-flip-|flop~)"
                                (lispy--sub-slurp-backward 1)) 1))
  (should (eq (lispy-with-v el "(progn\n  foo-bar-baz-flip-|flop~)"
                                (lispy--sub-slurp-backward 4)) 4))
  (should (eq (lispy-with-v el "(progn\n  foo-bar-baz-flip-|flop~)"
                                (lispy--sub-slurp-backward 5)) 4))
  (should (eq (lispy-with-v el "(progn\n  foo-bar-baz-flip-|flop~)"
                                (lispy--sub-slurp-backward 5)
                                (lispy--sub-slurp-backward 1)) nil)))

(ert-deftest lispy-slurp ()
  (should (string= (lispy-with "()|(a) (b) (c)" ">")
                   "((a))| (b) (c)"))
  (should (string= (lispy-with "()|(a) (b) (c)" ">>")
                   "((a) (b))| (c)"))
  (should (string= (lispy-with "()|(a) (b) (c)" ">>>")
                   "((a) (b) (c))|"))
  (should (string= (lispy-with "()|(a) (b) (c)" ">>>>")
                   "((a) (b) (c))|"))
  (should (string= (lispy-with "(a) (b) (c)|()" ">")
                   "(a) (b) (c ())|"))
  (should (string= (lispy-with "(a) (b) (c) |()" ">>")
                   "(a) |((b) (c) )"))
  (should (string= (lispy-with "(a) (b) (c) |()" ">>>")
                   "|((a) (b) (c) )"))
  (should (string= (lispy-with "(a) (b) (c) |()" ">>>>")
                   "|((a) (b) (c) )"))
  (should (string= (lispy-with "(insert)|\"foo\"" ">")
                   "(insert \"foo\")|"))
  (should (string= (lispy-with "(foo) #_~(bar)| (baz)" ">")
                   "(foo) #_~(bar) (baz)|"))
  (should (string= (lispy-with "(foo) #_|(bar)~ (baz)" ">")
                   "(foo) |#_(bar)~ (baz)"))
  (should (string= (lispy-with "|(a) (b) (c)" "m>")
                   "~(a) (b)| (c)"))
  (should (string= (lispy-with "(progn\n  ~foo|-bar-baz-flip-flop)" (lispy-slurp 1))
                   "(progn\n  ~foo-bar|-baz-flip-flop)"))
  (should (string= (lispy-with "(progn\n  ~foo|-bar-baz-flip-flop)" (lispy-slurp 2))
                   "(progn\n  ~foo-bar-baz|-flip-flop)"))
  (should (string= (lispy-with "(progn\n  ~foo|-bar-baz-flip-flop)" (lispy-slurp 3))
                   "(progn\n  ~foo-bar-baz-flip|-flop)"))
  (should (string= (lispy-with "(progn\n  ~foo|-bar-baz-flip-flop)" (lispy-slurp 4))
                   "(progn\n  ~foo-bar-baz-flip-flop|)"))
  (should (string= (lispy-with "(progn\n  ~foo|-bar-baz-flip-flop)" (lispy-slurp 5))
                   "(progn\n  ~foo-bar-baz-flip-flop|)"))
  (should (string= (lispy-with "(progn\n  foo-bar-baz-flip-|flop~)" (lispy-slurp 1))
                   "(progn\n  foo-bar-baz-|flip-flop~)"))
  (should (string= (lispy-with "(progn\n  foo-bar-baz-flip-|flop~)" (lispy-slurp 2))
                   "(progn\n  foo-bar-|baz-flip-flop~)"))
  (should (string= (lispy-with "(progn\n  foo-bar-baz-flip-|flop~)" (lispy-slurp 3))
                   "(progn\n  foo-|bar-baz-flip-flop~)"))
  (should (string= (lispy-with "(progn\n  foo-bar-baz-flip-|flop~)" (lispy-slurp 4))
                   "(progn\n  |foo-bar-baz-flip-flop~)"))
  (should (string= (lispy-with "(progn\n  foo-bar-baz-flip-|flop~)" (lispy-slurp 5))
                   "(progn\n  |foo-bar-baz-flip-flop~)"))
  (should (string= (lispy-with "(progn\n  |foo-bar~-baz-flip-flop)" (lispy-slurp 1))
                   "(progn\n  |foo-bar~-baz-flip-flop)"))
  (should (string= (lispy-with "()|   foo" (lispy-slurp 1))
                   "(foo)|"))
  (should (string= (lispy-with "(progn\n  ~(foo)|\n  ;; comment 1\n  ;; comment 2\n  (bar))" ">")
                   "(progn\n  ~(foo)\n  ;; comment 1\n  ;; comment 2|\n  (bar))"))
  (should (string= (lispy-with "(progn\n  (foo)\n  ;; comment 1\n  ;; comment 2\n  |(bar)~)" ">")
                   "(progn\n  (foo)\n  |;; comment 1\n  ;; comment 2\n  (bar)~)"))
  (should (string= (lispy-with "((a)| b c)" (lispy-slurp -1))
                   "((a b c)|)"))
  (should (string= (lispy-with "()|(a) (b)\n(c) (d)" (lispy-slurp -1))
                   "((a) (b))|\n(c) (d)"))
  (should (string= (lispy-with "(a (b (c)| d) e)" (lispy-slurp -1))
                   "(a (b (c d)|) e)"))
  (should (string= (lispy-with "(a b |(c))" (lispy-slurp -1))
                   "(|(a b c))"))
  (should (string= (lispy-with "(a) (b)\n(c) (d) |((e))" (lispy-slurp -1))
                   "(a) (b)\n|((c) (d) (e))"))
  (should (string= (lispy-with "(a (b |(c) d) e)" (lispy-slurp -1))
                   "(a (|(b c) d) e)"))
  (should (string= (lispy-with "()|(a) (b)\n(c) (d)" (lispy-slurp 0))
                   "((a) (b)\n (c) (d))|"))
  (should (string= (lispy-with "(()|(a) (b)\n (c) (d))\n(e) (f)" (lispy-slurp 0))
                   "(((a) (b)\n  (c) (d))|)\n(e) (f)"))
  (should (string= (lispy-with "(a (b (c)| d) e)" (lispy-slurp 0))
                   "(a (b (c d)|) e)"))
  (should (string= (lispy-with "(a) (b)\n(c) (d) |((e))" (lispy-slurp 0))
                   "|((a) (b)\n (c) (d) (e))"))
  (should (string= (lispy-with "(a) (b)\n((c) (d)\n (e) |((f)))" (lispy-slurp 0))
                   "(a) (b)\n(|((c) (d)\n  (e) (f)))"))
  (should (string= (lispy-with "(a (b |(c) d) e)" (lispy-slurp 0))
                   "(a (|(b c) d) e)"))
  (should (string= (lispy-with "(~|a (b c) d\n e f)" (lispy-slurp -1))
                   "(~a (b c) d|\n e f)"))
  (should (string= (lispy-with "(~|a (b c) d\n e f)" (lispy-slurp 0))
                   "(~a (b c) d\n e f|)"))
  (should (string= (lispy-with "(a b\n   c (d e) |f~)" (lispy-slurp -1))
                   "(a b\n   |c (d e) f~)"))
  (should (string= (lispy-with "(a b\n   c (d e) |f~)" (lispy-slurp 0))
                   "(|a b\n   c (d e) f~)"))
  (should (string= (lispy-with "(a (~|b c) d)" (lispy-slurp -1))
                   "(a (~b c|) d)"))
  (should (string= (lispy-with "(a (~|b c) d)" (lispy-slurp 0))
                   "(a (~b c|) d)"))
  (should (string= (lispy-with "(a (b |c~) d)" (lispy-slurp -1))
                   "(a (|b c~) d)"))
  (should (string= (lispy-with "(a (b |c~) d)" (lispy-slurp 0))
                   "(a (|b c~) d)"))
  (should (string= (lispy-with "~|a b c" (lispy-slurp -1))
                   "~a b c|"))
  (should (string= (lispy-with "~|a b c" (lispy-slurp 0))
                   "~a b c|"))
  (should (string= (lispy-with "a b |c~" (lispy-slurp -1))
                   "|a b c~"))
  (should (string= (lispy-with "a b |c~" (lispy-slurp 0))
                   "|a b c~"))
  ;; before a multi-line list
  (should (string= (lispy-with "()| (a\n    b)" (lispy-slurp -1))
                   "((a\n  b))|"))
  (should (string= (lispy-with "~|(a\n b)" (lispy-slurp -1))
                   "~(a\n b)|")))

(ert-deftest lispy-barf ()
  (should (string= (lispy-with "((a) (b) (c))|" "<")
                   "((a) (b))| (c)"))
  (should (string= (lispy-with "((a) (b) (c))|" "<<")
                   "((a))| (b) (c)"))
  (should (string= (lispy-with "((a) (b) (c))|" "<<<")
                   "()|(a) (b) (c)"))
  (should (string= (lispy-with "((a) (b) (c))|" "<<<<")
                   "()|(a) (b) (c)"))
  (should (string= (lispy-with "|((a) (b) (c))" "<")
                   "(a) |((b) (c))"))
  (should (string= (lispy-with "|((a) (b) (c))" "<<")
                   "(a) (b) |((c))"))
  (should (string= (lispy-with "|((a) (b) (c))" "<<<")
                   "(a) (b) (c)|()"))
  (should (string= (lispy-with "|((a) (b) (c))" "<<<<")
                   "(a) (b) (c)|()"))
  (should (string= (lispy-with "(progn\n  ~foo-bar-baz-flip-flop|)" (lispy-barf 1))
                   "(progn\n  ~foo-bar-baz-flip|-flop)"))
  (should (string= (lispy-with "(progn\n  ~foo-bar-baz-flip-flop|)" (lispy-barf 2))
                   "(progn\n  ~foo-bar-baz|-flip-flop)"))
  (should (string= (lispy-with "(progn\n  ~foo-bar-baz-flip-flop|)" (lispy-barf 3))
                   "(progn\n  ~foo-bar|-baz-flip-flop)"))
  (should (string= (lispy-with "(progn\n  ~foo-bar-baz-flip-flop|)" (lispy-barf 4))
                   "(progn\n  ~foo|-bar-baz-flip-flop)"))
  (should (string= (lispy-with "(progn\n  ~foo-bar-baz-flip-flop|)" (lispy-barf 5))
                   "(progn\n  ~foo|-bar-baz-flip-flop)"))
  (should (string= (lispy-with "(progn\n  |foo-bar-baz-flip-flop~)" (lispy-barf 1))
                   "(progn\n  foo-|bar-baz-flip-flop~)"))
  (should (string= (lispy-with "(progn\n  |foo-bar-baz-flip-flop~)" (lispy-barf 2))
                   "(progn\n  foo-bar-|baz-flip-flop~)"))
  (should (string= (lispy-with "(progn\n  |foo-bar-baz-flip-flop~)" (lispy-barf 3))
                   "(progn\n  foo-bar-baz-|flip-flop~)"))
  (should (string= (lispy-with "(progn\n  |foo-bar-baz-flip-flop~)" (lispy-barf 4))
                   "(progn\n  foo-bar-baz-flip-|flop~)"))
  (should (string= (lispy-with "(progn\n  |foo-bar-baz-flip-flop~)" (lispy-barf 5))
                   "(progn\n  foo-bar-baz-flip-|flop~)"))
  (should (string= (lispy-with "(progn\n  ~(foo)\n  ;; comment 1\n  ;; comment 2|\n  (bar))" "<")
                   "(progn\n  ~(foo)|\n  ;; comment 1\n  ;; comment 2\n  (bar))"))
  (should (string= (lispy-with "(progn\n  (foo)\n  ~;; bar|\n  (baz))" "<")
                   "(progn\n  (foo)\n  ~;; bar|\n  (baz))")))

(ert-deftest lispy-slurp-or-barf-right ()
  (should (string= (lispy-with "()|(a) (b) (c)" (lispy-slurp-or-barf-right 1))
                   "((a))| (b) (c)"))
  (should (string= (lispy-with "()|(a) (b) (c)" (lispy-slurp-or-barf-right 2))
                   "((a) (b))| (c)"))
  (should (string= (lispy-with "()|(a) (b) (c)" (lispy-slurp-or-barf-right 3))
                   "((a) (b) (c))|"))
  (should (string= (lispy-with "()|(a) (b) (c)" (lispy-slurp-or-barf-right 4))
                   "((a) (b) (c))|"))
  (should (string= (lispy-with "|((a) (b) (c))" (lispy-slurp-or-barf-right 1))
                   "(a) |((b) (c))"))
  (should (string= (lispy-with "|((a) (b) (c))" (lispy-slurp-or-barf-right 2))
                   "(a) (b) |((c))"))
  (should (string= (lispy-with "|((a) (b) (c))" (lispy-slurp-or-barf-right 3))
                   "(a) (b) (c)|()"))
  (should (string= (lispy-with "|((a) (b) (c))" (lispy-slurp-or-barf-right 4))
                   "(a) (b) (c)|()"))
  (should (string= (lispy-with "(insert)|\"foo\"" (lispy-slurp-or-barf-right 1))
                   "(insert \"foo\")|"))
  (should (string= (lispy-with "(foo) #_~(bar)| (baz)" (lispy-slurp-or-barf-right 1))
                   "(foo) #_~(bar) (baz)|"))
  (should (string= (lispy-with "(progn\n  ~foo|-bar-baz-flip-flop)" (lispy-slurp-or-barf-right 1))
                   "(progn\n  ~foo-bar|-baz-flip-flop)"))
  (should (string= (lispy-with "(progn\n  ~foo|-bar-baz-flip-flop)" (lispy-slurp-or-barf-right 2))
                   "(progn\n  ~foo-bar-baz|-flip-flop)"))
  (should (string= (lispy-with "(progn\n  ~foo|-bar-baz-flip-flop)" (lispy-slurp-or-barf-right 3))
                   "(progn\n  ~foo-bar-baz-flip|-flop)"))
  (should (string= (lispy-with "(progn\n  ~foo|-bar-baz-flip-flop)" (lispy-slurp-or-barf-right 4))
                   "(progn\n  ~foo-bar-baz-flip-flop|)"))
  (should (string= (lispy-with "(progn\n  ~foo|-bar-baz-flip-flop)" (lispy-slurp-or-barf-right 5))
                   "(progn\n  ~foo-bar-baz-flip-flop|)"))
  (should (string= (lispy-with "(progn\n  |foo-bar-baz-flip-flop~)" (lispy-slurp-or-barf-right 1))
                   "(progn\n  foo-|bar-baz-flip-flop~)"))
  (should (string= (lispy-with "(progn\n  |foo-bar-baz-flip-flop~)" (lispy-slurp-or-barf-right 2))
                   "(progn\n  foo-bar-|baz-flip-flop~)"))
  (should (string= (lispy-with "(progn\n  |foo-bar-baz-flip-flop~)" (lispy-slurp-or-barf-right 3))
                   "(progn\n  foo-bar-baz-|flip-flop~)"))
  (should (string= (lispy-with "(progn\n  |foo-bar-baz-flip-flop~)" (lispy-slurp-or-barf-right 4))
                   "(progn\n  foo-bar-baz-flip-|flop~)"))
  (should (string= (lispy-with "(progn\n  |foo-bar-baz-flip-flop~)" (lispy-slurp-or-barf-right 5))
                   "(progn\n  foo-bar-baz-flip-|flop~)"))
  (should (string= (lispy-with "()|   foo" (lispy-slurp-or-barf-right 1))
                   "(foo)|"))
  (should (string= (lispy-with "(progn\n  ~(foo)|\n  ;; comment 1\n  ;; comment 2\n  (bar))" (lispy-slurp-or-barf-right 1))
                   "(progn\n  ~(foo)\n  ;; comment 1\n  ;; comment 2|\n  (bar))")))

(ert-deftest lispy-slurp-or-barf-left ()
  (should (string= (lispy-with "((a) (b) (c))|" (lispy-slurp-or-barf-left 1))
                   "((a) (b))| (c)"))
  (should (string= (lispy-with "((a) (b) (c))|" (lispy-slurp-or-barf-left 2))
                   "((a))| (b) (c)"))
  (should (string= (lispy-with "((a) (b) (c))|" (lispy-slurp-or-barf-left 3))
                   "()|(a) (b) (c)"))
  (should (string= (lispy-with "((a) (b) (c))|" (lispy-slurp-or-barf-left 4))
                   "()|(a) (b) (c)"))
  (should (string= (lispy-with "(a) (b) (c) |()" (lispy-slurp-or-barf-left 2))
                   "(a) |((b) (c) )"))
  (should (string= (lispy-with "(a) (b) (c) |()" (lispy-slurp-or-barf-left 3))
                   "|((a) (b) (c) )"))
  (should (string= (lispy-with "(a) (b) (c) |()" (lispy-slurp-or-barf-left 4))
                   "|((a) (b) (c) )"))
  (should (string= (lispy-with "(progn\n  ~foo-bar-baz-flip-flop|)" (lispy-slurp-or-barf-left 1))
                   "(progn\n  ~foo-bar-baz-flip|-flop)"))
  (should (string= (lispy-with "(progn\n  ~foo-bar-baz-flip-flop|)" (lispy-slurp-or-barf-left 2))
                   "(progn\n  ~foo-bar-baz|-flip-flop)"))
  (should (string= (lispy-with "(progn\n  ~foo-bar-baz-flip-flop|)" (lispy-slurp-or-barf-left 3))
                   "(progn\n  ~foo-bar|-baz-flip-flop)"))
  (should (string= (lispy-with "(progn\n  ~foo-bar-baz-flip-flop|)" (lispy-slurp-or-barf-left 4))
                   "(progn\n  ~foo|-bar-baz-flip-flop)"))
  (should (string= (lispy-with "(progn\n  ~foo-bar-baz-flip-flop|)" (lispy-slurp-or-barf-left 5))
                   "(progn\n  ~foo|-bar-baz-flip-flop)"))
  (should (string= (lispy-with "(progn\n  ~(foo)\n  ;; comment 1\n  ;; comment 2|\n  (bar))" (lispy-slurp-or-barf-left 1))
                   "(progn\n  ~(foo)|\n  ;; comment 1\n  ;; comment 2\n  (bar))"))
  (should (string= (lispy-with "(progn\n  (foo)\n  ~;; bar|\n  (baz))" (lispy-slurp-or-barf-left 1))
                   "(progn\n  (foo)\n  ~;; bar|\n  (baz))"))
  (should (string= (lispy-with "(foo) #_|(bar)~ (baz)" (lispy-slurp-or-barf-left 1))
                   "(foo) |#_(bar)~ (baz)"))
  (should (string= (lispy-with "(progn\n  foo-bar-baz-flip-|flop~)" (lispy-slurp-or-barf-left 1))
                   "(progn\n  foo-bar-baz-|flip-flop~)"))
  (should (string= (lispy-with "(progn\n  foo-bar-baz-flip-|flop~)" (lispy-slurp-or-barf-left 2))
                   "(progn\n  foo-bar-|baz-flip-flop~)"))
  (should (string= (lispy-with "(progn\n  foo-bar-baz-flip-|flop~)" (lispy-slurp-or-barf-left 3))
                   "(progn\n  foo-|bar-baz-flip-flop~)"))
  (should (string= (lispy-with "(progn\n  foo-bar-baz-flip-|flop~)" (lispy-slurp-or-barf-left 4))
                   "(progn\n  |foo-bar-baz-flip-flop~)"))
  (should (string= (lispy-with "(progn\n  foo-bar-baz-flip-|flop~)" (lispy-slurp-or-barf-left 5))
                   "(progn\n  |foo-bar-baz-flip-flop~)"))
  (should (string= (lispy-with "(progn\n  |foo-bar~-baz-flip-flop)" (lispy-slurp-or-barf-left 1))
                   "(progn\n  |foo-bar~-baz-flip-flop)"))
  (should (string= (lispy-with "(progn\n  (foo)\n  ;; comment 1\n  ;; comment 2\n  |(bar)~)" (lispy-slurp-or-barf-left 1))
                   "(progn\n  (foo)\n  |;; comment 1\n  ;; comment 2\n  (bar)~)")))

(ert-deftest lispy-splice ()
  (should (string= (lispy-with "(|(a) (b) (c))" "/")
                   "(a |(b) (c))"))
  (should (string= (lispy-with "((a) |(b) (c))" "/")
                   "((a) b |(c))"))
  (should (string= (lispy-with "(|(a) (b) (c))" "///")
                   "|(a b c)"))
  (should (string= (lispy-with "((a) (b) (c)|)" "/")
                   "((a) (b)| c)"))
  (should (string= (lispy-with "((a) (b) (c)|)" "//")
                   "((a)| b c)"))
  (should (string= (lispy-with "((a) (b) (c)|)" "///")
                   "(a b c)|"))
  (should (string= (lispy-with "|(a b c)" "/")
                   "|a b c"))
  (should (string= (lispy-with "(a b c)|" "/")
                   "a b c|"))
  (should (string= (lispy-with "(a ~'(b c)|)" "/")
                   "(a ~b c|)"))
  (should (string= (lispy-with "(a |'(b c)~)" "/")
                   "(a |b c~)"))
  (should (string= (lispy-with "(a '(b c)|)" "/")
                   "(a b c)|"))
  (should (string= (lispy-with "(asdf)\n(progn\n  |(foo)\n  (bar))\n(asdf)" "//")
                   "(asdf)\n|(progn\n  foo\n  bar)\n(asdf)"))
  (should (string= (lispy-with "(asdf)\n(progn\n  (foo)\n  (bar)|)\n(asdf)" "//")
                   "(asdf)\n(progn\n  foo\n  bar)|\n(asdf)"))
  ;; test that quotes also get deleted
  (should (string= (lispy-with "'|(a)" "/")
                   "|a"))
  (should (string= (lispy-with "(,@|(a))" "/")
                   "|(a)"))
  (should (string= (lispy-with "#2A|((a b) (0 1))" "/")
                   "|(a b) (0 1)"))
  ;; let splicing
  (should (string= (lispy-with "(let (foo)\n  |(let ((bar (point)))\n    (baz)))" "/")
                   "(let (foo\n      |(bar (point)))\n  (baz))"))
  (should (string= (lispy-with "(let ((foo (point)))\n  |(let ((bar (1+ foo)))\n    (baz)))" "/")
                   "(let* ((foo (point))\n       |(bar (1+ foo)))\n  (baz))"))
  (should (string= (lispy-with "|(let (foo)\n  (let ((bar (point)))\n    (baz)))" "/")
                   "let |(foo)\n  (let ((bar (point)))\n    (baz))"))
  (should (string= (lispy-with clojure "(let [foo 10]\n  |(let [bar 20]\n    (baz)))" "/")
                   "|(let [foo 10\n      bar 20]\n  (baz))")))

(ert-deftest lispy-barf-to-point ()
  (should (string= (lispy-with "((a) (b)| (c))" (lispy-barf-to-point nil))
                   "((a) (b))| (c)"))
  (should (string= (lispy-with "((a) (b) |(c))" (lispy-barf-to-point nil))
                   "((a) (b))| (c)"))
  (should (string= (lispy-with "((a)| (b) (c))" (lispy-barf-to-point nil))
                   "((a))| (b) (c)"))
  (should (string= (lispy-with "(|(a) (b) (c))" (lispy-barf-to-point nil))
                   "()| (a) (b) (c)"))
  (should (string= (lispy-with "((a) (|b) (c))" (lispy-barf-to-point nil))
                   "((a) ()| b (c))"))
  (should (string= (lispy-with "((a|\n  b\n  c))" (lispy-barf-to-point nil))
                   "((a)|\n b\n c)"))
  (should (string= (lispy-with "((a\n  b|\n  c))" (lispy-barf-to-point nil))
                   "((a\n  b)|\n c)"))
  (should (string= (lispy-with "(a \"|b\" c)" (lispy-barf-to-point nil))
                   "(a \"|b\" c)"))
  (should (string= (lispy-with "(a |\"b\" c)" (lispy-barf-to-point nil))
                   "(a)| \"b\" c"))
  (should (string= (lispy-with "((a) |(b) (c))" (lispy-barf-to-point t))
                   "(a) |((b) (c))"))
  (should (string= (lispy-with "((a)| (b) (c))" (lispy-barf-to-point t))
                   "(a) |((b) (c))"))
  (should (string= (lispy-with "((a) (b) |(c))" (lispy-barf-to-point t))
                   "(a) (b) |((c))"))
  (should (string= (lispy-with "((a) (b) (c)|)" (lispy-barf-to-point t))
                   "(a) (b) (c) |()"))
  (should (string= (lispy-with "((a) (b|) (c))" (lispy-barf-to-point t))
                   "((a) b |() (c))"))
  (should (string= (lispy-with "((a\n  b\n  |c))" (lispy-barf-to-point t))
                   "(a\n b\n |(c))"))
  (should (string= (lispy-with "((a\n  |b\n  c))" (lispy-barf-to-point t))
                   "(a\n |(b\n  c))"))
  (should (string= (lispy-with "(a \"b|\" c)" (lispy-barf-to-point t))
                   "(a \"b|\" c)"))
  (should (string= (lispy-with "(a \"b\"| c)" (lispy-barf-to-point t))
                   "a \"b\" |(c)"))
  (should (string= (lispy-with "a|" (lispy-barf-to-point nil))
                   "a|"))
  (should (string= (lispy-with "((a) (b) (c))|" (lispy-barf-to-point nil))
                   "((a) (b) (c))|"))
  (should (string= (lispy-with "((a b c|))" (lispy-barf-to-point nil))
                   "((a b c)|)"))
  (should (string= (lispy-with "((a b c)|)" (lispy-barf-to-point nil))
                   "((a b c))|"))
  (should (string= (lispy-with "((|a b c))" (lispy-barf-to-point t))
                   "(|(a b c))"))
  (should (string= (lispy-with "(|(a b c))" (lispy-barf-to-point t))
                   "|((a b c))")))

(ert-deftest lispy-raise ()
  (should (string= (lispy-with "(if (and |(pred1) (pred2))\n    (thing1)\n  (thing2))" "r")
                   "(if |(pred1)\n    (thing1)\n  (thing2))"))
  (should (string= (lispy-with "(if (and (pred1) |(pred2))\n    (thing1)\n  (thing2))" "r")
                   "(if |(pred2)\n    (thing1)\n  (thing2))"))
  (should (string= (lispy-with "(if (and (pred1)| (pred2))\n    (thing1)\n  (thing2))" "r")
                   "(if (pred1)|\n    (thing1)\n  (thing2))"))
  (should (string= (lispy-with "(if (and (pred1) (pred2)|)\n    (thing1)\n  (thing2))" "r")
                   "(if (pred2)|\n    (thing1)\n  (thing2))"))
  (should (string= (lispy-with "(if (and (pred1) (pred2))\n    |(thing1)\n  (thing2))" "r")
                   "|(thing1)"))
  (should (string= (lispy-with "(if (and (pred1) (pred2))\n    (thing1)|\n  (thing2))" "r")
                   "(thing1)|"))
  (should (string= (lispy-with "(if (and (pred1) (pred2))\n    (thing1)\n  |(thing2))" "r")
                   "|(thing2)"))
  (should (string= (lispy-with "(if (and (pred1) (pred2))\n    (thing1)\n  (thing2)|)" "r")
                   "(thing2)|"))
  (should (string= (lispy-with "(foo (bar |(baz)))" "r")
                   "(foo |(baz))"))
  (should (string= (lispy-with "(foo (bar |(baz)))" "2r")
                   "|(baz)"))
  (should (string= (lispy-with "(foo (bar |(baz)~))" "r")
                   "(foo |(baz)~)"))
  (should (string= (lispy-with "(foo (bar |(baz)~))" "2r")
                   "|(baz)~"))
  (should (string= (lispy-with "(a (f~oob|ar) c)" "r") "(a ~oob| c)"))
  (should (string= (lispy-with "(a (f|oob~ar) c)" "r") "(a |oob~ c)"))
  (should (string= (lispy-with "(\n     |(foo))" "r") "|(foo)"))
  ;; a bug in `indent-sexp' http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16852
  ;; (should (string= (lispy-with "(|(\n  progn\n  ))" "r") "|(\n progn\n )"))
  )

(ert-deftest lispy-raise-some ()
  (should (string= (lispy-with "(if (and |(pred1) (pred2))\n    (thing1)\n  (thing2))" "R")
                   "(if |(pred1) (pred2)\n    (thing1)\n  (thing2))"))
  (should (string= (lispy-with "(if (and (pred1) |(pred2))\n    (thing1)\n  (thing2))" "R")
                   "(if |(pred2)\n    (thing1)\n  (thing2))"))
  (should (string= (lispy-with "(if (and (pred1) (pred2))\n    |(thing1)\n  (thing2))" "R")
                   "|(thing1)\n(thing2)"))
  (should (string= (lispy-with "(progn\n  |(foo)\n  nil)" "R")
                   "|(foo)\nnil"))
  (should (string= (lispy-with "(a\n b\n (foo)|\n c)" "R")
                   "a\nb\n(foo)|"))
  (should (string= (lispy-with "|(foo)" "R")
                   "|(foo)"))
  (should (string= (lispy-with "(foo)|" "R")
                   "(foo)|")))

(ert-deftest lispy-convolute ()
  (should (string= (lispy-with "(when (pred)\n  (let ((x 1))\n    |(foo)\n    (bar)))" "C")
                   "(let ((x 1))\n  (when (pred)\n    |(foo))\n  (bar))"))
  (should (string= (lispy-with "(when (pred)\n  (let ((x 1))\n    |(foo)\n    (bar)))" "CC")
                   "(when (pred)\n  (let ((x 1))\n    |(foo)\n    (bar)))"))
  (should (string= (lispy-with "(+ 1 (* 2 ~3|))" "C")
                   "(* 2 (+ 1 ~3|))"))
  (should (string= (lispy-with "(+ 1 (* 2 |3~))" "C")
                   "(* 2 (+ 1 |3~))"))
  (should (string= (lispy-with "(asdf\n (when (pred)\n   (let ((x 1))\n     (foo)\n     |(bar))))"
                               "2C")
                   "(when (pred)\n  (let ((x 1))\n    (foo)\n    (asdf\n     |(bar))))"))
  (should (string= (lispy-with "(takes-two\n  (takes-three\n   |(takes-four 1 2 3 4)\n   second\n   third)\n  other-second)"
                               "C")
                   "(takes-three\n (takes-two\n  |(takes-four 1 2 3 4)\n  other-second)\n second\n third)"))
  (should (string= (lispy-with "(with-current-buffer buf\n  (let ((beg x)\n        (end y))\n    |(insert \" \")\n    (delete-region beg end)\n    (point)))"
                               "0C")
                   "(let ((beg x)\n      (end y))\n  (with-current-buffer buf\n    |(insert \" \")\n    (delete-region beg end)\n    (point)))")))

(ert-deftest lispy-join ()
  (should (string= (lispy-with "(foo) |(bar)" "+")
                   "(foo |bar)"))
  (should (string= (lispy-with "(foo)| (bar)" "+")
                   "(foo bar)|"))
  (should (string= (lispy-with "\"a series\"\n \" of st|rings\"" (kbd "M-J"))
                   "\"a series of st|rings\""))
  (should (string= (lispy-with "\"a series\"\n |\" of strings\"" (kbd "M-J"))
                   "\"a series| of strings\""))
  (should (string= (lispy-with "\"a series|\"\n \" of strings\"" (kbd "M-J"))
                   "\"a series| of strings\""))
  (should (string= (lispy-with "\"a series|\"\n \" of strings\"" (kbd "M-J"))
                   "\"a series| of strings\""))
  (should (string= (lispy-with "|\"a series\"\n \" of strings\"" (kbd "M-J"))
                   "|\"a series of strings\"")))

(ert-deftest lispy-split ()
  (should (string= (lispy-with "(foo |bar)" (kbd "M-j"))
                   "(foo)\n|(bar)"))
  (should (string= (lispy-with "\"five |is right out\"" (kbd "M-j"))
                   "\"five \"\n|\"is right out\""))
  (should (string= (lispy-with "|\"five is right out\"" (kbd "M-j"))
                   "\n|\"five is right out\""))
  (should (string= (lispy-with "|\"five is right out\""
                               (kbd "M-f") (kbd "M-j")
                               (kbd "M-f") (kbd "M-j")
                               (kbd "M-f") (kbd "M-j"))
                   "\"five\"\n\" is\"\n\" right\"\n|\" out\""))
  (should (string= (lispy-with "|\"five is right out\""
                               (kbd "M-f") (kbd "M-j")
                               (kbd "M-f") (kbd "M-j")
                               (kbd "M-f") (kbd "M-j")
                               (kbd "M-J") (kbd "M-J") (kbd "M-J"))
                   "\"five is right| out\""))
  (should (string= (lispy-with "(defun charge! ()\n  (message \"[mayham]\")\n  |(run-away))" (kbd "M-j"))
                   "(defun charge! ()\n  (message \"[mayham]\"))\n|((run-away))"))
  (should (string= (lispy-with "(defun charge! ()\n  |(message \"[mayham]\")\n  (run-away))" (kbd "M-j"))
                   "(defun charge! ())\n|((message \"[mayham]\")\n (run-away))"))
  (should (string= (lispy-with "\"this|\nand that\"" (kbd "M-j"))
                   "\"this\"\n|\"and that\""))
  (should (string= (lispy-with "(let ((a 1)\n      |(b 2)\n      (c 3))\n  (+ a b c))" (kbd "M-j"))
                   "(let ((a 1))\n  |(let ((b 2)\n        (c 3))\n    (+ a b c)))"))
  (should (string= (lispy-with "(let ((a 1)\n      (b 2)\n      |(c 3))\n  (+ a b c))" (kbd "M-j"))
                   "(let ((a 1)\n      (b 2))\n  |(let ((c 3))\n    (+ a b c)))"))
  (should (string= (lispy-with clojure "[1 2 |5]" (kbd "M-j"))
                   "[1 2]\n|[5]"))
  (should (string= (lispy-with clojure "{:chapter 2 |:verse 9}" (kbd "M-j"))
                   "{:chapter 2}\n|{:verse 9}"))
  (should (string= (lispy-with "(let ((x 1))\n  (setq y 2|\n        z 3))" (kbd "M-j"))
                   "(let ((x 1))\n  (setq y 2)\n  |(\n   z 3))")))

(ert-deftest lispy-move-up ()
  (should (string= (lispy-with "((a) (b) |(c))" "w")
                   "((a) |(c) (b))"))
  (should (string= (lispy-with "((a) (b) |(c))" "ww")
                   "(|(c) (a) (b))"))
  (should (string= (lispy-with "((a) (b) |(c))" "www")
                   "(|(c) (a) (b))"))
  (should (string= (lispy-with "((a) (b) (c)|)" "w")
                   "((a) (c)| (b))"))
  (should (string= (lispy-with "((a) (b) (c)|)" "ww")
                   "((c)| (a) (b))"))
  (should (string= (lispy-with "((a) (b) (c)|)" "www")
                   "((c)| (a) (b))"))
  (should (string= (lispy-with "((a) |(b) (c))" "m>w")
                   "(~(b) (c)| (a))"))
  (should (string= (lispy-with "((a) |(b) (c))" "mjw")
                   "((a) ~(c)| (b))"))
  (should (string= (lispy-with "(foo b|ar)"
                               (kbd "M-m")
                               "w")
                   "(~bar| foo)"))
  (should (string= (lispy-with "(~foo| bar)" "w")
                   "(~foo| bar)"))
  (should (string= (lispy-with clojure "{&foo| bar}" "w")
                   "{&foo| bar}"))
  (should (string= (lispy-with clojure "[&foo| bar]" "w")
                   "[&foo| bar]"))
  (should (string= (lispy-with "(put :foo 1\n     :bar 2\n     |:baz '(1 2 3)~)"
                               (lispy-move-up 2))
                   "(put :foo 1\n     |:baz '(1 2 3)~\n     :bar 2)"))
  (should (string= (lispy-with "(put :foo 1\n     :bar 2\n     ~:baz '(1 2 3)|)"
                               (lispy-move-up 2))
                   "(put :foo 1\n     ~:baz '(1 2 3)|\n     :bar 2)"))
  (should (string= (lispy-with "(foo baz |(bar))" "w")
                   "(foo |(bar) baz)"))
  (should (string= (lispy-with "('(b) '|(a) '(c))" "w")
                   "('|(a) '(b) '(c))"))
  (should (string= (lispy-with "('(b) '(a)| '(c))" "w")
                   "('(a)| '(b) '(c))"))
  (unless (version<= emacs-version "24.3.1")

    (should (string= (lispy-with ";;; b\n(bar)\n;;; c\n(baz)\n|;;; a\n(foo)" "w")
                     ";;; b\n(bar)\n|;;; a\n(foo)\n;;; c\n(baz)"))
    (should (string= (let ((lispy-outline ";;;"))
                       (lispy-with ";;; b\n(bar)\n;;; c\n(baz)\n|;;; a\n(foo)" "2w"))
                     "|;;; a\n(foo)\n;;; b\n(bar)\n;;; c\n(baz)")))
  (should (string= (lispy-with "(sexp (one)\n      ;; comment\n      |(two))" "w")
                   "(sexp (one)\n      |(two)\n      ;; comment\n      )")))

(ert-deftest lispy-move-up-region ()
  (should (string= (lispy-with "(lisp sugar-~free|)" "w")
                   "(lisp |free~-sugar)"))
  (should (string= (lispy-with "(lisp sugar-~free|)" "ww")
                   "(lisp |free~-sugar)"))
  (should (string= (lispy-with "sugar-~free|-lisp" "w")
                   "|free~-sugar-lisp"))
  (should (string= (lispy-with "sugar-free-|lisp~" "w")
                   "sugar-~lisp|-free"))
  (should (string= (lispy-with "sugar-free-|lisp~" "ww")
                   "|lisp~-sugar-free")))

(ert-deftest lispy-move-down-region ()
  (should (string= (lispy-with "(~sugar|-free lisp)" "s")
                   "(free-~sugar| lisp)"))
  (should (string= (lispy-with "(|sugar~-free lisp)" "s")
                   "(free-|sugar~ lisp)"))
  (should (string= (lispy-with "(|sugar~-free lisp)" "ss")
                   "(free-|sugar~ lisp)"))
  (should (string= (lispy-with clojure "(list\n  {&:bar \"foo\"|\n   :foo \"bar\"})" "2s")
                   "(list\n  {:foo \"bar\"\n   &:bar \"foo\"|})")))

(ert-deftest lispy-move-down ()
  (should (string= (lispy-with "(|(a) (b) (c))" "s")
                   "((b) |(a) (c))"))
  (should (string= (lispy-with "(|(a) (b) (c))" "ss")
                   "((b) (c) |(a))"))
  (should (string= (lispy-with "(|(a) (b) (c))" "sss")
                   "((b) (c) |(a))"))
  (should (string= (lispy-with "((a)| (b) (c))" "s")
                   "((b) (a)| (c))"))
  (should (string= (lispy-with "((a)| (b) (c))" "ss")
                   "((b) (c) (a)|)"))
  (should (string= (lispy-with "((a)| (b) (c))" "sss")
                   "((b) (c) (a)|)"))
  (should (string= (lispy-with "(|(a) (b) (c))" "m]s")
                   "((c) ~(a) (b)|)"))
  (should (string= (lispy-with "(f|oo bar)"
                               (kbd "M-m")
                               "s")
                   "(bar ~foo|)"))
  (should (string= (lispy-with "(foo ~bar|)" "s")
                   "(foo ~bar|)"))
  (should (string= (lispy-with "(put :foo 1\n     ~:baz '(1 2 3)|\n     :bar 2)"
                               (lispy-move-down 2))
                   "(put :foo 1\n     :bar 2\n     ~:baz '(1 2 3)|)"))
  (should (string= (lispy-with "(put :foo 1\n     |:baz '(1 2 3)~\n     :bar 2)"
                               (lispy-move-down 2))
                   "(put :foo 1\n     :bar 2\n     |:baz '(1 2 3)~)"))
  (should (string= (lispy-with "(foo |(bar) baz)" "s")
                   "(foo baz |(bar))"))
  (should (string= (lispy-with "('|(a) '(b) '(c))" "s")
                   "('(b) '|(a) '(c))"))
  (should (string= (lispy-with "('(a)| '(b) '(c))" "s")
                   "('(b) '(a)| '(c))"))
  (should (string= (lispy-with "(a)\n|(b)" "s")
                   "(a)\n|(b)"))
  (unless (version<= emacs-version "24.3.1")
    (should (string= (lispy-with "|;;; a\n(foo)\n;;; b\n(bar)\n;;; c\n(baz)" "s")
                     ";;; b\n(bar)\n|;;; a\n(foo)\n;;; c\n(baz)"))
    (should (string= (lispy-with "|;;; a\n(foo)\n;;; b\n(bar)\n;;; c\n(baz)" "2s")
                     ";;; b\n(bar)\n;;; c\n(baz)\n|;;; a\n(foo)"))))

(ert-deftest lispy-clone ()
  (should (string= (lispy-with "(foo)|" "c")
                   "(foo)\n(foo)|"))
  (should (string= (lispy-with "(list\n (foo)|)" "c")
                   "(list\n (foo)\n (foo)|)"))
  (should (string= (lispy-with "|(foo)" "c")
                   "|(foo)\n(foo)"))
  (should (string= (lispy-with "(list\n |(foo))" "c")
                   "(list\n |(foo)\n (foo))"))
  (should (string= (lispy-with "(foo ~(bar)|)" "c")
                   "(foo ~(bar)|\n     (bar))"))
  (should (string= (lispy-with "(foo |(bar)~)" "c")
                   "(foo |(bar)~\n     (bar))"))
  (should (string= (lispy-with "(progn '|(foo))" "c")
                   "(progn '|(foo)\n       '(foo))"))
  (should (string= (lispy-with "(progn '(foo)|)" "c")
                   "(progn '(foo)\n       '(foo)|)"))
  (should (string= (lispy-with "(defun ~function-name| ()\n  (bar))" "c")
                   "(defun ~function-name|\n    function-name ()\n  (bar))"))
  (should (string= (lispy-with "|(+ 1 2)\n;; => 3" "c")
                   "(+ 1 2)\n;; => 3\n|(+ 1 2)")))

(ert-deftest lispy-oneline ()
  (should (string= (lispy-with "|(defun abc (x)\n  \"def.\"\n  (+ x\n     x\n     x))" "O")
                   "|(defun abc (x) \"def.\" (+ x x x))"))
  (should (string= (lispy-with "(defun abc (x)\n  \"def.\"\n  (+ x\n     x\n     x))|" "O")
                   "(defun abc (x) \"def.\" (+ x x x))|"))
  (should (string= (lispy-with "|(defun foo ()\n  ;; comment\n  (bar)\n  (baz))" "O")
                   ";; comment\n|(defun foo () (bar) (baz))"))
  (should (string= (lispy-with "(progn\n  |;; comment 1\n  ;; comment 2\n  (foo))" "O")
                   "(progn\n  |;; comment 1 comment 2\n  (foo))"))
  (should (string= (lispy-with "|(defun test ()\n  ;; comment 1\n  ;; comment 2\n  ;; comment 3\n  (foo))" "O")
                   ";; comment 1\n;; comment 2\n;; comment 3\n|(defun test () (foo))"))
  (should (string= (lispy-with "[1\n 2\n 3\n 4\n 5]|" "O")
                   "[1 2 3 4 5]|")))

(ert-deftest lispy-multiline ()
  (should (string= (lispy-with "|(defun abc (x) \"def.\" (+ x x x) (foo) (bar))"
                               (lispy-multiline))
                   "|(defun abc (x)\n  \"def.\" (+ x x x)\n  (foo)\n  (bar))"))
  (should (string= (lispy-with "|(defun abc(x)\"def.\"(+ x x x)(foo)(bar))"
                               (lispy-multiline))
                   "|(defun abc(x)\n  \"def.\"(+ x x x)\n  (foo)\n  (bar))"))
  (should (string= (lispy-with "|(\"King Arthur\" \"Sir Lancelot\" \"Sir Robin\")"
                               (lispy-multiline))
                   "|(\"King Arthur\"\n \"Sir Lancelot\"\n \"Sir Robin\")")))

(ert-deftest lispy-alt-multiline ()
  (let ((lispy-multiline-threshold nil))
    (should (string= (lispy-with "|(defvar knights '(lancelot robin galahad bedevere) \"We're knights of the round table...\")" "M")
                     "|(defvar knights '(lancelot\n                  robin\n                  galahad\n                  bedevere)\n  \"We're knights of the round table...\")"))
    (should (string= (lispy-with "|(defun abc (x) \"def.\" (+ x x x) (foo) (bar))" "M")
                     "|(defun abc (x)\n  \"def.\"\n  (+\n   x\n   x\n   x)\n  (foo)\n  (bar))"))
    (should (string= (lispy-with "|(defun abc(x)\"def.\"(+ x x x)(foo)(bar))" "M")
                     "|(defun abc (x)\n  \"def.\"\n  (+\n   x\n   x\n   x)\n  (foo)\n  (bar))"))
    (should (string= (lispy-with "|(\"King Arthur\" \"Sir Lancelot\" \"Sir Robin\")" "M")
                     "|(\"King Arthur\"\n \"Sir Lancelot\"\n \"Sir Robin\")"))
    (should (string= (lispy-with clojure "|{:king \"Arthur\" :knight \"Lancelot\"}" "M")
                     "|{:king \"Arthur\"\n :knight \"Lancelot\"}"))
    (should (string= (lispy-with clojure "#|{:king \"Arthur\" :knight \"Lancelot\"}" "M")
                     "#|{:king \"Arthur\"\n  :knight \"Lancelot\"}"))
    (should (string= (lispy-with clojure "|(let [name \"Launcelot\" quest 'grail color 'blue] (print \"Right. Off you go\"))" "M")
                     "|(let [name \"Launcelot\"\n      quest 'grail\n      color 'blue]\n  (print\n   \"Right. Off you go\"))"))
    (should (string= (lispy-with clojure "|(when long-enough-line #:car{:name \"a-name\" :type \"a-type\"} #:bike{:name \"a-name\" :type \"a-type\"})" "M")
                     "|(when\n    long-enough-line\n    #:car{:name \"a-name\"\n          :type \"a-type\"}\n    #:bike{:name \"a-name\"\n           :type \"a-type\"})"))
    (should (string= (lispy-with "(eval-when-compile(require'cl)(require'org))|" "M")
                     "(eval-when-compile\n  (require 'cl)\n  (require 'org))|"))
    (should (string= (lispy-with "|(defgroup lispy nil \"List navigation and editing for the Lisp family.\" :group 'bindings :prefix \"lispy-\")" "M")
                     "|(defgroup lispy nil\n  \"List navigation and editing for the Lisp family.\"\n  :group 'bindings\n  :prefix \"lispy-\")"))
    (should (string= (lispy-with "|(setq expr '(defvar defun defcustom defface))" "M")
                     "|(setq expr\n      '(defvar\n        defun\n        defcustom\n        defface))"))
    (should (string= (lispy-with "|(setq expr `(defvar defun defcustom defface))" "M")
                     "|(setq expr\n      `(defvar\n           defun\n         defcustom\n         defface))"))
    (should (string= (lispy-with "|(defun foo (bar) \"Doc.\"(interactive \"p\") (let ((var1 (foo-1 bar 1)) (var2 1) (var-3 (foo (foo bar)))) (baz bar)))" "M")
                     "|(defun foo (bar)\n  \"Doc.\"\n  (interactive \"p\")\n  (let ((var1 (foo-1\n               bar\n               1))\n        (var2 1)\n        (var-3 (foo\n                (foo\n                 bar))))\n    (baz\n     bar)))"))
    (should (string= (lispy-with "|(if (and (string= ,left \"(\")\n         ;; (= ?\\( (aref (this-command-keys-vector) 0))\n         )\n    (insert \"(\")\n  (insert ,left ,right)\n  (backward-char 1))" "M")
                     "|(if (and (string=\n          ,left\n          \"(\")\n         ;; (= ?\\( (aref (this-command-keys-vector) 0))\n         )\n    (insert\n     \"(\")\n  (insert\n   ,left\n   ,right)\n  (backward-char\n   1))"))
    (should (string= (lispy-with "|(foo . bar)" "M")
                     "|(foo . bar)"))
    (should (string= (lispy-with "|(defvar knights-alist '((\"Sir Launcelot\" . \"the Brave\") (\"Sir Galahad\" . \"the Pure\") (\"Sir Robin\" . \"Not-quite-so-brave-as-Sir-Launcelot\")) \"The wise Sir Bedemir was the first to join King Arthur's\\n  knights, but other illustrious names were soon to follow:\")" "M")
                     "|(defvar knights-alist '((\"Sir Launcelot\" . \"the Brave\")\n                        (\"Sir Galahad\" . \"the Pure\")\n                        (\"Sir Robin\" . \"Not-quite-so-brave-as-Sir-Launcelot\"))\n  \"The wise Sir Bedemir was the first to join King Arthur's\n  knights, but other illustrious names were soon to follow:\")"))
    (should (string= (lispy-with "|(foo\n ;; bar\n bar)" "M")
                     "|(foo\n ;; bar\n bar)"))
    (should (string= (lispy-with "|(lispy--multiline-1 '(let let*) t)" "M")
                     "|(lispy--multiline-1\n '(let\n   let*)\n t)"))
    (should (string= (lispy-with "|(format\n      #(\"error: [h]: first, [j]: next, [k]: prev, [SPC]: rep.\"\n        8 9 (face hydra-face-red)\n        20 21 (face hydra-face-red)\n        31 32 (face hydra-face-red)\n        42 45 (face hydra-face-red)))" "M")
                     "|(format\n #(\"error: [h]: first, [j]: next, [k]: prev, [SPC]: rep.\"\n   8 9 (face\n        hydra-face-red)\n   20 21 (face\n          hydra-face-red)\n   31 32 (face\n          hydra-face-red)\n   42 45 (face\n          hydra-face-red)))"))
    (should (string= (lispy-with "[1 2 3 4 5]|" "M")
                     "[1\n 2\n 3\n 4\n 5]|"))))

(ert-deftest lispy-comment ()
  (should (string= (lispy-with "(defun foo ()\n  (let (a b c)\n    (cond ((s1)\n           |(s2)\n           (s3)))))" ";")
                   "(defun foo ()\n  (let (a b c)\n    (cond ((s1)\n           ;; (s2)\n           |(s3)))))"))
  (should (string= (lispy-with "(defun foo ()\n  (let (a b c)\n    (cond ((s1)\n           |(s2)\n           (s3)))))" ";;")
                   "(defun foo ()\n  (let (a b c)\n    (cond |((s1)\n           ;; (s2)\n           ;; (s3)\n           ))))"))
  (should (string-match "(defun foo ()\n  (let (a b c)\n    |(cond ;; ((s1)\n          ;;  ;; (s2)\n          ;;  ;; (s3)\n          ;;  )\n     *)))"
                        (lispy-with "(defun foo ()\n  (let (a b c)\n    (cond ((s1)\n           |(s2)\n           (s3)))))" ";;;")))
  (should (string-match "(defun foo ()\n  |(let (a b c)\n    ;; (cond ;; ((s1)\n    ;;       ;;  ;; (s2)\n    ;;       ;;  ;; (s3)\n    ;;       ;;  )\n    ;;   *)\n   *))"
                        (lispy-with "(defun foo ()\n  (let (a b c)\n    (cond ((s1)\n           |(s2)\n           (s3)))))" ";;;;")))
  (should (string-match "|(defun foo ()\n  ;; (let (a b c)\n  ;;   ;; (cond ;; ((s1)\n  ;;   ;;       ;;  ;; (s2)\n  ;;   ;;       ;;  ;; (s3)\n  ;;   ;;       ;;  )\n  ;;   ;;  *)\n  ;;   )\n  )"
                        (lispy-with "(defun foo ()\n  (let (a b c)\n    (cond ((s1)\n           |(s2)\n           (s3)))))" ";;;;;")))
  (should (string-match "|;; (defun foo ()\n;;   ;; (let (a b c)\n;;   ;;   ;; (cond ;; ((s1)\n;;   ;;   ;;       ;;  ;; (s2)\n;;   ;;   ;;       ;;  ;; (s3)\n;;   ;;   ;;       ;;  )\n;;   ;;   ;;  *)\n;;   ;;   )\n;;   )"
                        (lispy-with "(defun foo ()\n  (let (a b c)\n    (cond ((s1)\n           |(s2)\n           (s3)))))" ";;;;;;")))
  (should (string= (lispy-with ";; line| 1\n;; line 2\n (a b c)\n ;; line 3" (lispy-comment 2))
                   "line| 1\nline 2\n (a b c)\n ;; line 3"))
  (should (string= (lispy-with ";; line 1\n;; line 2|\n (a b c)\n ;; line 3" (lispy-comment 2))
                   "line 1\nline 2|\n (a b c)\n ;; line 3"))
  (should (string= (lispy-with "(|\"foo\"\n (bar)\n baz)" ";")
                   "(;; \"foo\"\n |(bar)\n baz)"))
  (should (string= (lispy-with "(foo|)" ";")
                   "(foo\n ;; |\n )"))
  (should (string= (lispy-with "((foo)| (bar))" ";")
                   "((foo)\n ;; |\n (bar))"))
  (should (string= (lispy-with "((foo) (bar)|)" ";")
                   "((foo) (bar)\n ;; |\n )"))
  (should (string= (lispy-with "|\n(defun foo ())" ";;;")
                   ";;;###autoload\n|(defun foo ())"))
  (should (string= (lispy-with "(list\n |foo)" ";")
                   "(list\n |;; foo\n )"))
  (should (string= (lispy-with "(list\n| foo)" ";")
                   "(list\n |;; foo\n )"))
  (should (string= (lispy-with "(list\n |foo\n bar)" ";")
                   "(list\n |;; foo\n bar)"))
  (should (string= (lispy-with "|foo bar\nbaz" ";")
                   "|;; foo bar\nbaz"))
  (should (string= (lispy-with "(list\n foo\n |1 (2\n    3)\n bar)" ";")
                   "(list\n foo\n |;; 1 (2\n ;;    3)\n bar)"))
  (should (string= (lispy-with "(defun foo ()|\n  (bar))" ";")
                   "(defun foo ()\n  ;; |\n  (bar))"))
  (should (string= (lispy-with "(list \\|)" ";")
                   "(list \\;|)"))
  (should (string= (lispy-with "(list #|)" ";")
                   "(list #;|)"))
  ;; With single semicolons
  (let ((lispy-comment-use-single-semicolon t))
    (should (string= (lispy-with "(foo)|" ";")
                     "(foo)                                   ; |"))
    (should (string= (lispy-with "(foo)                                   ; |" ";")
                     "(foo) ;; |"))
    (should (string= (lispy-with "((a)| (b))" ";")
                     "((a)                                    ; |\n (b))"))
    (should (string= (lispy-with "((a)                                    ; |\n (b))" ";")
                     "((a) ;; |\n (b))"))
    (should (string= (lispy-with "(foo|)" ";")
                     "(foo                                    ; |\n )"))
    (should (string= (lispy-with "(foo                                    ; |\n )" ";")
                     "(foo ;; |\n )"))))

(ert-deftest lispy-move-end-of-line ()
  ;; (should (string= (lispy-with "(foo (bar #\\x \"|baz \\\\ quux\") zot)"
  ;;                              (move-end-of-line 1))
  ;;                  "(foo (bar #\\x \"baz \\\\ quux\") zot)|"))
  ;; (should (string= (lispy-with "(foo (bar #\\x \"|baz \\\\ quux\") zot)" "\C-e\C-e")
  ;;                  "(foo (bar #\\x \"baz \\\\ quux\"|) zot)"))
  ;; (should (string= (lispy-with "\"fo|o\nbar\" baz"
  ;;                              (lispy-move-end-of-line)
  ;;                              (lispy-move-end-of-line))
  ;;                  "\"foo\nbar\"| baz"))
  (should (string= (lispy-with "\"foo|\nbar\" baz" "\C-e")
                   "\"foo\nbar\"| baz")))

(ert-deftest lispy-move-beginning-of-line ()
  (should (string= (lispy-with "(mapc\n (lambda (x) (* |x x))\n '(1 2 3))" (kbd "C-a"))
                   "(mapc\n| (lambda (x) (* x x))\n '(1 2 3))"))
  (should (string= (lispy-with "(mapc\n (lambda (x) (* |x x))\n '(1 2 3))"
                               (kbd "C-a")
                               (kbd "C-a"))
                   "(mapc\n |(lambda (x) (* x x))\n '(1 2 3))")))

(ert-deftest lispy-string-oneline ()
  (should (string= (lispy-with "\"foo\nb|ar\n\"" (lispy-string-oneline))
                   "\"foo\\nbar\\n\"|")))

(ert-deftest lispy-stringify ()
  (should (string= (lispy-with "(a\n b\n (foo)\n c)|" "S")
                   "\"(a\n b\n (foo)\n c)|\""))
  (should (string= (lispy-with "(progn |(1 2 3))" "S")
                   "(progn \"|(1 2 3)\")"))
  (should (string= (lispy-with "(foo |(bar #\\x \"baz \\\\ quux\") zot)" "S")
                   "(foo \"|(bar #\\\\x \\\"baz \\\\\\\\ quux\\\")\" zot)"))
  (should (string= (lispy-with "(list ~one|\n      two\n      five)" "S")
                   "(list ~\"one\"|\n      two\n      five)"))
  (should (string= (lispy-with "(list ~one|\n      two\n      five)" "SjSjS")
                   "(list \"one\"\n      \"two\"\n      ~\"five\"|)")))

(ert-deftest lispy-teleport ()
  ;; should be able to cancel
  (should (string= (lispy-with "(a |(b))"
                               (execute-kbd-macro (kbd "t ESC")))
                   "(a |(b))"))
  (should (string= (lispy-with "(a (b)|)"
                               (execute-kbd-macro (kbd "t ESC")))
                   "(a (b)|)"))
  (should (string= (lispy-with "((a) ~b|)"
                               (execute-kbd-macro (kbd "t ESC")))
                   "((a) ~b|)"))
  (should (string= (lispy-with "(let ((x))\n  '|(foo bar)\n  (baz))"
                               (execute-kbd-macro (kbd "tc ESC")))
                   "(let ((x '|(foo bar)))\n  (baz))"))

  (should (string= (lispy-with "((a) |b~)"
                               (execute-kbd-macro (kbd "t ESC")))
                   "((a) |b~)")))

(ert-deftest lispy-eval ()
  (should (string= (lispy-with-v el "(+ 2 2)|" (lispy-eval 1)) "4"))
  ;; (should (string= (lispy-with "|(+ 2 2)" "2e") "|(+ 2 2)\n;; => 4"))
  )

(ert-deftest lispy-eval-and-insert ()
  (should (string= (lispy-with "(+ 2 2)|" "E")
                   "(+ 2 2)\n4|")))

(ert-deftest lispy-eval-and-replace ()
  (should (string= (lispy-with "|(setq foo 42)\n(list foo foo)" "ej"
                               (lispy-eval-and-replace))
                   "(setq foo 42)\n|(42 42)"))
  (should (string= (lispy-with "|(setq foo 42)\n(list foo foo)" "ej3m"
                               (lispy-eval-and-replace))
                   "(setq foo 42)\n|(list foo 42)")))

(ert-deftest lispy-eval-and-comment ()
  (should (string= (lispy-with "(|(number-sequence 1 10))" "2e")
                   "(|(number-sequence 1 10)\n ;; => (1 2 3 4 5 6 7 8 9 10)\n )"))
  (should (string= (lispy-with "((number-sequence 1 10)|)" "2e")
                   "((number-sequence 1 10)|\n ;; => (1 2 3 4 5 6 7 8 9 10)\n )")))

(ert-deftest lispy-quotes ()
  (should (string= (lispy-with "(frob grovel |full lexical)" "\"")
                   "(frob grovel \"|\" full lexical)"))
  (should (string= (lispy-with "(foo \"bar |baz\" quux)" "\"")
                   "(foo \"bar \\\"|\\\"baz\" quux)"))
  (should (string= (lispy-with "\"(fo|o)\"" (lispy-quotes 1))
                   "(fo|o)"))
  (should (string= (lispy-with "\"(foo)\"\n|(bar)" "mk2\"")
                   "~(foo)|\n(bar)"))
  (should (string= (lispy-with "(message \"say |hi~\")" "\"")
                   "(message \"say |\\\"hi\\\"~\")"))
  (should (string= (lispy-with "|\"foo\"" "\"")
                   "\"|\" \"foo\""))
  (should (string= (lispy-with "(list exp|erts)" (kbd "C-u") (kbd "\""))
                   "(list \"exp|erts\")"))
  (should (string= (lispy-with "(list \"exp|erts\")"
                               (kbd "C-u") (kbd "\""))
                   "(list exp|erts)"))
  (should (string= (lispy-with "(list ~\"experts\"|)" "\"")
                   "(list ~\"\\\"experts\\\"\"|)"))
  (should (string= (lispy-with "(list |\"experts\"~)" "\"")
                   "(list |\"\\\"experts\\\"\"~)")))

(ert-deftest lispy--normalize-1 ()
  (should (string= (lispy-with "|(foo (bar)baz)" (lispy--normalize-1))
                   "|(foo (bar) baz)"))
  (should (string= (lispy-with "(foo (bar)baz)|" (lispy--normalize-1))
                   "(foo (bar) baz)|"))
  (should (string= (lispy-with "|(bar\n  foo )" (lispy--normalize-1))
                   "|(bar\n foo)"))
  (should (string= (lispy-with "|(foo \")\")" (lispy--normalize-1))
                   "|(foo \")\")"))
  (should (string= (lispy-with "|(foo     \n bar)" (lispy--normalize-1))
                   "|(foo\n bar)"))
  (should (string= (lispy-with "|(require' foo)" (lispy--normalize-1))
                   "|(require 'foo)"))
  (should (string= (lispy-with clojure
                               "|(expr ~(expr) ~'expr '~(expr) ~'(expr) ~@(expr))"
                               (lispy--normalize-1))
                   "|(expr ~(expr) ~'expr '~(expr) ~'(expr) ~@(expr))"))
  (let ((clojure-align-forms-automatically t))
    (should (string= (lispy-with clojure
                                 "|{:some-key 10\n :key2 20}" (lispy--normalize-1))
                     "|{:some-key 10\n :key2     20}"))))

(ert-deftest lispy--sexp-normalize ()
  (should (equal
           (lispy--sexp-normalize
            '(progn
              (ly-raw comment "foo")
              (ly-raw newline)))
           '(progn
             (ly-raw comment "foo")
             (ly-raw newline)))))

(ert-deftest lispy--remove-gaps ()
  (should (string= (lispy-with "((a) |(c))" (lispy--remove-gaps))
                   "((a) |(c))")))

(ert-deftest clojure-thread-macro ()
  ;; changes indentation
  (require 'cider nil t)
  (should (string= (lispy-with clojure "|(map sqr (filter odd? [1 2 3 4 5]))" "2(->>]<]<]wwlM")
                   "(->>\n [1 2 3 4 5]\n (map sqr)\n (filter odd?))|")))

(ert-deftest lispy-mark ()
  (should (string= (lispy-with "|;; abc\n;; def\n;; ghi" (kbd "C-M-,"))
                   "~;; abc\n;; def\n;; ghi|"))
  (should (string= (lispy-with ";; a|bc\n;; def\n;; ghi" (kbd "C-M-,"))
                   "~;; abc\n;; def\n;; ghi|"))
  (should (string= (lispy-with ";; abc\n|;; def\n;; ghi" (kbd "C-M-,"))
                   "~;; abc\n;; def\n;; ghi|"))
  (should (string= (lispy-with ";; abc\n;; def\n;; ghi|" (kbd "C-M-,"))
                   "~;; abc\n;; def\n;; ghi|")))

(ert-deftest lispy-mark-symbol ()
  (should (string= (lispy-with "(foo |\"bar\")" (kbd "M-m"))
                   "(foo ~\"bar\"|)"))
  (should (string= (lispy-with "(foo \"bar|\")" (kbd "M-m"))
                   "(foo ~\"bar\"|)"))
  (should (string= (lispy-with "(mapc #'ta|unt knights)" (kbd "M-m"))
                   "(mapc ~#'taunt| knights)"))
  (should (string= (lispy-with "|(foo)" (kbd "M-m"))
                   "(~foo|)"))
  (should (string= (lispy-with "(foo|)" (kbd "M-m"))
                   "(~foo|)"))
  (should (string= (lispy-with "|[foo]" (kbd "M-m"))
                   "[~foo|]"))
  (should (string= (lispy-with clojure "|{foo}" (kbd "M-m"))
                   "{&foo|}"))
  (should (string= (lispy-with "(foo \"|bar\")" (kbd "M-m"))
                   "(foo \"~bar|\")"))
  (should (string= (lispy-with "\"See `plu|mage'.\"" (kbd "M-m"))
                   "\"See ~`plumage'|.\""))
  (should (string= (lispy-with ";; See `plu|mage'." (kbd "M-m"))
                   ";; See ~`plumage'|."))
  (should (string= (lispy-with "(list {:key args})|" (kbd "M-m"))
                   "(list {:key |args~})"))
  (should (string= (lispy-with "|[\"string with spaces\"]" (kbd "M-m"))
                   "[\"~string| with spaces\"]"))
  (should (string= (lispy-with clojure "|{\"string with spaces\"}" (kbd "M-m"))
                   "{\"&string| with spaces\"}"))
  (should (string= (lispy-with "(defn fname \"string\"| )" (kbd "M-m"))
                   "(defn fname ~\"string\"| )"))
  (should (string= (lispy-with "(defn fname \"string\"| [] (symbols in a form))" (kbd "M-m"))
                   "(defn fname ~\"string\"| [] (symbols in a form))"))
  (should (string= (lispy-with "|(\"a\")" (kbd "M-m"))
                   "(\"~a|\")"))
  (should (string= (lispy-with "(\"string\"  |)" (kbd "M-m"))
                   "(~\"string\"|  )"))
  (should (string= (lispy-with "(:keyword| (form))" (kbd "M-m"))
                   "(~:keyword| (form))")))

(ert-deftest lispy--read ()
  (should (equal (lispy--read "(mu4e-mail)")
                 '(mu4e-mail)))
  (should (equal (lispy--read "(progn
                                 #'foo
                                 (ly-raw function foo)
                                 (function foo)
                                 \"#'bar\"
                                 \"(ly-raw)\"
                                 #'bar)")
                 '(progn (ly-raw newline)
                   (ly-raw function foo)
                   (ly-raw newline)
                   (ly-raw raw function foo)
                   (ly-raw newline)
                   #'foo
                   (ly-raw newline)
                   (ly-raw string "\"#'bar\"")
                   (ly-raw newline)
                   (ly-raw string "\"(ly-raw)\"")
                   (ly-raw newline)
                   (ly-raw function bar))))
  (should (equal (lispy--read "(helm :sources
                                     `((name . \"this defun\")
                                       (match-strict .
                                                     (lambda (x)))))")
                 '(helm :sources (ly-raw newline)
                   (ly-raw \` ((name (ly-raw dot)
                                     (ly-raw string "\"this defun\""))
                               (ly-raw newline)
                               (match-strict (ly-raw dot)
                                             (ly-raw newline)
                                             (lambda (x))))))))
  ;; (should (equal
  ;;          (lispy-with clojure
  ;;           "|(fn* [p1__7041#] (+ 1 p1__7041#))" "i")
  ;;          "|(fn* [p1__7041#] (+ 1 p1__7041#))"))
  (should (equal
           (lispy-with clojure
                       "|(s/? ::spec)" "i")
           "|(s/? ::spec)"))
  (should (equal
           (lispy--prin1-to-string
            (lispy--read "#<marker (moves after insertion) at 280 in *Customize Group: Lispy Faces*>")
            0 'emacs-lisp-mode)
           "#<marker (moves after insertion) at 280 in *Customize Group: Lispy Faces*>"))
  (should (equal
           (lispy--prin1-to-string
            (lispy--read "(1 2 3 1 2 . #2)")
            0 'emacs-lisp-mode)
           "(1 2 3 1 2 . #2)"))
  (let ((major-mode 'emacs-lisp-mode))
    (should (equal (lispy--read "(progn `(lambda () ,(+ 2 2) ,@(number-sequence 1 3)))")
                   '(progn
                     (ly-raw \` (lambda (ly-raw empty) (ly-raw \, (+ 2 2)) (ly-raw comma-splice (number-sequence 1 3))))))))
  (should (equal
           (lispy--read "#(\"]\" 0 1 (face hydra-face-red))")
           '(ly-raw clojure-lambda ((ly-raw string "\"]\"")
                                    0 1 (face hydra-face-red)))))
  (should (equal
           (lispy--read "#p\"path\"")
           '(ly-raw lisp-macro "#p\"path\"")))
  (should (equal
           (lispy--read "#m(foo bar)")
           '(ly-raw lisp-macro "#m(foo bar)")))
  (should (equal
           (lispy--read ",(or body)")
           '(ly-raw \, (or body))))
  (should (equal (lispy-with-v clj
                     "|(list \\a \\b \\. \\, \\c \\space \\tab \\u03A9)"
                   (lispy--read (lispy--string-dwim)))
                 '((ly-raw clojure-symbol "list")
                   (ly-raw clojure-char "\\a")
                   (ly-raw clojure-char "\\b")
                   (ly-raw clojure-char "\\.")
                   (ly-raw clojure-char "\\,")
                   (ly-raw clojure-char "\\c")
                   (ly-raw clojure-char "\\space")
                   (ly-raw clojure-char "\\tab")
                   (ly-raw clojure-char "\\u03A9"))))
  (should (equal (lispy-with-v clj
                     "|(str \\! \\@ \\# \\$ \\% \\& \\*)"
                   (lispy--read (lispy--string-dwim)))
                 '((ly-raw clojure-symbol "str")
                   (ly-raw clojure-char "\\!")
                   (ly-raw clojure-char "\\@")
                   (ly-raw clojure-char "\\#")
                   (ly-raw clojure-char "\\$")
                   (ly-raw clojure-char "\\%")
                   (ly-raw clojure-char "\\&")
                   (ly-raw clojure-char "\\*"))))
  (should (equal (lispy-with-v clj
                     "|(foo \"#_(bar)\")"
                   (lispy--read (lispy--string-dwim)))
                 '((ly-raw clojure-symbol "foo")
                   (ly-raw string "\"#_(bar)\""))))
  (should (equal (lispy-with-v clj
                     "|{:a {:nested \"map\"}}"
                   (lispy--read (lispy--string-dwim)))
                 '(ly-raw clojure-map
                   ((ly-raw clojure-symbol ":a")
                    (ly-raw clojure-map
                     ((ly-raw clojure-symbol ":nested")
                      (ly-raw string "\"map\"")))))))
  (should (equal (lispy-with-v clj
                     "|#(swap! foo assoc :bar (. % .-value))"
                   (lispy--read (lispy--string-dwim)))
                 '(ly-raw clojure-lambda
                   ((ly-raw clojure-symbol "swap!")
                    (ly-raw clojure-symbol "foo")
                    (ly-raw clojure-symbol "assoc")
                    (ly-raw clojure-symbol ":bar")
                    ((ly-raw clojure-symbol ".") % (ly-raw clojure-symbol ".-value"))))))
  (should (equal (lispy--read ":.name")
                 '(ly-raw clojure-keyword ":.name"))))

(ert-deftest lispy-tick ()
  (should (string= (lispy-with "|" "'") "'|"))
  (should (string= (lispy-with "|" "`") "`|"))
  (should (string= (lispy-with "~\"right\"|" "'")
                   "~right|"))
  (should (string= (lispy-with "|\"right\"~" "'")
                   "|right~"))
  (should (string= (lispy-with clojure "foo|" "'")
                   "foo '|"))
  (should (string= (lispy-with clojure "foo|" " ~'")
                   "foo ~'|"))
  (should (string= (lispy-with "(setq foo ~bar|)" "'")
                   "(setq foo ~'bar|)"))
  (should (string= (lispy-with "(setq foo ~'bar|)" "'")
                   "(setq foo ~bar|)")))

(ert-deftest lispy-underscore ()
  (should (string= (lispy-with clojure "(list |[1 2 3]\n      [3 4 5])" "_")
                   "(list #_|[1 2 3]\n      [3 4 5])"))
  (should (string= (lispy-with clojure "(list #_|[1 2 3]\n      [3 4 5])" "_")
                   "(list |[1 2 3]\n      [3 4 5])"))
  (should (string= (lispy-with clojure "(list [1 2 3]|\n      [3 4 5])" "_")
                   "(list #_[1 2 3]|\n      [3 4 5])"))
  (should (string= (lispy-with clojure "(list #_[1 2 3]|\n      [3 4 5])" "_")
                   "(list [1 2 3]|\n      [3 4 5])")))

(ert-deftest lispy-to-lambda ()
  (should (string= (lispy-with "|(defun foo (x y)\n  (bar))" (lispy-to-lambda))
                   "|(lambda (x y)\n  (bar))"))
  (should (string= (lispy-with "(defun foo (x y)\n  |(bar))" (lispy-to-lambda))
                   "|(lambda (x y)\n  (bar))"))
  (should (string= (lispy-with "(defun foo (x y)\n  (bar))|" (lispy-to-lambda))
                   "|(lambda (x y)\n  (bar))")))

(ert-deftest lispy-parens ()
  (should (string= (lispy-with "'|(foo bar)" "1(")
                   "(| '(foo bar))"))
  (should (string= (lispy-with "'(foo bar)|" "1(")
                   "(| '(foo bar))"))
  (should (string= (lispy-with "\"a regex \\\\|\"" "(")
                   "\"a regex \\\\(|\\\\)\""))
  (let (lispy-parens-only-left-in-string-or-comment)
    (should (string= (lispy-with "\"|\"" "(")
                     "\"(|)\""))
    (should (string= (lispy-with ";; |" "(")
                     ";; (|)")))
  (should (string= (lispy-with "~(foo) (bar)|" "(")
                   "(| (foo) (bar))"))
  (should (string= (lispy-with "~foo (bar)|" "(")
                   "|(foo (bar))"))
  (should (string= (lispy-with "~foo (bar)|" "1(")
                   "(| foo (bar))"))
  (should (string= (lispy-with "(foo bar|)" "1(")
                   "(foo (| bar))"))
  (should (string= (lispy-with "(foo bar| )" "1(")
                   "(foo (| bar) )"))
  (should (string= (lispy-with "{|}" "(")
                   "{(|)}"))
  (should (string= (lispy-with "(defun foo (x)\n  |)" "1(")
                   "(defun foo (x)\n  (|))"))
  ;; test space-unless behavior
  (should (string= (lispy-with "a|" "(")
                   "a (|)"))
  (should (string= (lispy-with ",@|" "(")
                   ",@(|)"))
  (should (string= (lispy-with clojure "#|" "(")
                   "#(|)"))
  (should (string= (lispy-with clojure "#?@|" "(")
                   "#?@(|)"))
  (should (string= (lispy-with clojure "(map #|(+ % 1) '(1 2 3))" "2(")
                   "(map #(| (+ % 1)) '(1 2 3))")))

(ert-deftest lispy-braces ()
  (should (string= (lispy-with "\"a regex \\\\|\"" "{")
                   "\"a regex \\\\{|\\\\}\""))
  (should (string= (lispy-with "\"a string |" "{")
                   "\"a string {|}"))
  ;; test space-unless behavior
  (should (string= (lispy-with clojure "`|" "{")
                   "`{|}"))
  (should (string= (lispy-with clojure "^|" "{")
                   "^{|}"))
  (should (string= (lispy-with clojure "#my.record|" "{")
                   "#my.record{|}"))
  (should (string= (lispy-with clojure "symbol|" "{")
                   "symbol {|}")))

(ert-deftest lispy-brackets ()
  (should (string= (lispy-with "\"a regex \\\\|\"" "}")
                   "\"a regex \\\\[|\\\\]\""))
  (should (string= (lispy-with "\"a string |" "}")
                   "\"a string [|]"))
  ;; test space-unless behavior
  (should (string= (lispy-with clojure "`|" "}")
                   "`[|]"))
  (should (string= (lispy-with clojure "#my.klass_or_type_or_record|" "}")
                   "#my.klass_or_type_or_record[|]")))

(ert-deftest lispy-to-ifs ()
  (should (or (version<= emacs-version "24.3.1") (string= (lispy-with "|(cond ((looking-at \" *;\"))\n      ((and (looking-at \"\\n\")\n            (looking-back \"^ *\"))\n       (delete-blank-lines))\n      ((looking-at \"\\\\([\\n ]+\\\\)[^\\n ;]\")\n       (delete-region (match-beginning 1)\n                      (match-end 1))))"
                                                                      (lispy-to-ifs))
                                                          "|(if (looking-at \" *;\")\n    nil\n  (if (and (looking-at \"\\n\")\n           (looking-back \"^ *\"))\n      (delete-blank-lines)\n    (if (looking-at \"\\\\([\\n ]+\\\\)[^\\n ;]\")\n        (delete-region (match-beginning 1)\n                       (match-end 1)))))"))))

(ert-deftest lispy-to-cond ()
  (should (or (version<= emacs-version "24.3.1")
              (string= (lispy-with "|(if (looking-at \" *;\")\n    nil\n  (if (and (looking-at \"\\n\")\n           (looking-back \"^ *\"))\n      (delete-blank-lines)\n    (if (looking-at \"\\\\([\\n ]+\\\\)[^\\n ;]\")\n        (delete-region (match-beginning 1)\n                       (match-end 1)))))"
                                   (lispy-to-cond))
                       "|(cond ((looking-at \" *;\"))\n      ((and (looking-at \"\\n\")\n            (looking-back \"^ *\"))\n       (delete-blank-lines))\n      ((looking-at \"\\\\([\\n ]+\\\\)[^\\n ;]\")\n       (delete-region (match-beginning 1)\n                      (match-end 1))))")))
  (should (string= (lispy-with "|(cl-case question\n  (name\n   \"Sir Launcelot\")\n  ( quest\n   \"To seek the Holy Grail\")\n  (   favorite-color\n   \"Blue\")\n  (t\n   (error \"I don't know that!\")))"
                               (execute-kbd-macro "xc"))
                   "|(cond\n  ((eq question 'name)\n   \"Sir Launcelot\")\n  ((eq question 'quest)\n   \"To seek the Holy Grail\")\n  ((eq question 'favorite-color)\n   \"Blue\")\n  (t\n   (error \"I don't know that!\")))")))

(ert-deftest lispy-to-defun ()
  (should (string= (lispy-with "(foo bar)|" (lispy-to-defun))
                   "(defun foo (bar)\n  |)"))
  (should (string= (lispy-with "|(foo bar)" (lispy-to-defun))
                   "(defun foo (bar)\n  |)"))
  (should (string= (lispy-with "(foo)|" (lispy-to-defun))
                   "(defun foo ()\n  |)"))
  (should (string= (lispy-with "|(foo)" (lispy-to-defun))
                   "(defun foo ()\n  |)")))

(ert-deftest lispy-up-slurp ()
  (should (string= (lispy-with "(progn\n  (foo))\n|(bar)" "ok")
                   "(progn\n  (foo)\n  |(bar))"))
  (should (string= (lispy-with "(progn\n  (foo))\n(bar)|" "ok")
                   "(progn\n  (foo)\n  (bar)|)"))
  (should (string= (lispy-with "(progn\n  (foo))\n~(bar)|" "ok")
                   "(progn\n  (foo)\n  ~(bar)|)"))
  (should (string= (lispy-with "(progn\n  (foo))\n|(bar)~" "ok")
                   "(progn\n  (foo)\n  |(bar)~)"))
  (should (string= (lispy-with "(progn\n  (foo))\n|(bar)\n(baz)~" "ok")
                   "(progn\n  (foo)\n  |(bar)\n  (baz)~)"))
  (should (string= (lispy-with "[foo] |(bar)" "ok")
                   "[foo |(bar)]"))
  (should (string= (lispy-with "(progn\n  (foo))\n~(bar)\n(baz)|" "ok")
                   "(progn\n  (foo)\n  ~(bar)\n  (baz)|)"))
  (should (string= (lispy-with "(let ((a (1+))))\n|" (lispy-up-slurp))
                   "(let ((a (1+)))\n  |)"))
  (should (string= (lispy-with "(let ((a (1+)))\n  |)" (lispy-up-slurp))
                   "(let ((a (1+))\n      |))"))
  (should (string= (lispy-with "(let ((a (1+))\n      |))" (lispy-up-slurp))
                   "(let ((a (1+)\n        |)))"))
  (should (string= (lispy-with "(let ((a (1+)\n        |)))" (lispy-up-slurp))
                   "(let ((a (1+\n          |))))"))
  ;; no change should be made here
  (should (string= (lispy-with "(let ((a (1+\n          |))))" (lispy-up-slurp))
                   "(let ((a (1+\n          |))))")))

(ert-deftest lispy-indent-adjust-parens ()
  ;; fix incorrect indentation
  (should (string= (lispy-with "(a\n|)" (lispy-indent-adjust-parens 1))
                   "(a\n |)"))
  (should (string= (lispy-with "(a\n  |  )\n" (lispy-indent-adjust-parens 1))
                   "(a\n |)\n"))
  (should (string= (lispy-with "(a\n  ~(b c)\n   (d e)\n    (|f g)"
                               (lispy-indent-adjust-parens 1)
                               (deactivate-mark))
                   "(a\n (b c)\n (d e)\n (|f g)"))
  ;; just move point
  (should (string= (lispy-with "((a)\n| )" (lispy-indent-adjust-parens 1))
                   "((a)\n |)"))
  ;; don't do anything; shouldn't error or move point
  (should (string= (lispy-with "(a|)" (lispy-indent-adjust-parens 1))
                   "(a|)"))
  ;; otherwise call lispy-up-slurp
  (should (string= (lispy-with "(let ((a (1+))))\n|"
                               (lispy-indent-adjust-parens 1))
                   "(let ((a (1+)))\n  |)"))
  (should (string= (lispy-with "(progn\n  (foo))\n~(bar)\n(baz)|"
                               (lispy-indent-adjust-parens 1))
                   "(progn\n  (foo)\n  ~(bar)\n  (baz)|)"))
  ;; multiple symbols on same line
  (should (string= (lispy-with "(progn)\n|(foo) (bar)"
                               (lispy-indent-adjust-parens 1))
                   "(progn\n  |(foo) (bar))"))
  (should (string= (lispy-with "(foo (bar))\n|baz bif"
                               (lispy-indent-adjust-parens 1))
                   "(foo (bar)\n     |baz bif)"))
  ;; multi-line list
  (should (string= (lispy-with "(a)\n|(b\n c)" (lispy-indent-adjust-parens 1))
                   "(a\n |(b\n  c))"))
  ;; test counts
  (should (string= (lispy-with "(let ((a (1+))))\n|"
                               (lispy-indent-adjust-parens 3))
                   "(let ((a (1+)\n        |)))"))
  (should (string= (lispy-with "(let ((a (1+))))\n|"
                               (lispy-indent-adjust-parens 20))
                   "(let ((a (1+\n          |))))")))

(ert-deftest lispy-tab ()
  (should (string= (lispy-with "|(defun test?  (x) x)" "i")
                   "|(defun test? (x) x)"))
  (should (string= (lispy-with "|(list '{foobar)" "i")
                   "|(list '{foobar)"))
  (should (string= (lispy-with "|(setq x '(\n          \n          ))" "i")
                   "|(setq x '())"))
  (should (string= (lispy-with "|(eq (char-before) ?\\()" "i")
                   "|(eq (char-before) ?\\()"))
  (should (string= (lispy-with "`|[1  2  3]" "i")
                   "`|[1 2 3]"))
  (should (string= (lispy-with "   |(defun)" "i")
                   "|(defun)"))
  (should (string= (lispy-with "|;; comment 1\n;; comment 2" "i")
                   "|;; comment 1\n;; comment 2"))
  (should (string= (lispy-with "|(list \"\\\"\")" "i")
                   "|(list \"\\\"\")"))
  (should (string= (lispy-with "|(modify-syntax-entry ?' \"\\\"\" table)" "i")
                   "|(modify-syntax-entry ?' \"\\\"\" table)"))
  (should (string= (lispy-with clojure "|[#{}]" "i")
                   "|[#{}]"))
  (should (string= (lispy-with clojure "|[#:foo-bar{:name    \"test\"}]" "i")
                   "|[#:foo-bar{:name \"test\"}]"))
  (should (string= (lispy-with clojure "|(. object method)" "i")
                   "|(. object method)"))
  (should (string= (lispy-with clojure "|(range 1e9)" "i")
                   "|(range 1e9)"))
  (should (string= (lispy-with clojure "|[#db   {:a 1 :b 2}]" "i")
                   "|[#db {:a 1 :b 2}]"))
  (should (string= (lispy-with clojure "|[#js  [#js   {:a   true}]]" "i")
                   "|[#js[#js{:a true}]]"))
  (should (equal (lispy-with "|(pcase :bar\n    (`,pat pat))" "i")
                 "|(pcase :bar\n  (`,pat pat))"))
  (should (equal (lispy-with "'|(27 ?\\C-g)" "i")
                 "'|(27 ?\\C-g)"))
  (should (equal (lispy-with clojure "|[?id?,  t_a-b ,,,   Олег ]" "i")
                 "|[?id?, t_a-b ,,, Олег]"))
  (let ((clojure-align-forms-automatically nil))
    (should (string= (lispy-with clojure "|{\\a   \\b}" "i")
                     "|{\\a \\b}"))
    (should (string= (lispy-with clojure "|(list \\a   \\.   \\b)" "i")
                     "|(list \\a \\. \\b)"))
    (should (string= (lispy-with clojure "#?(:cljs   1   :clj 2)|" "i")
                     "#?(:cljs 1 :clj 2)|"))
    (should (string= (lispy-with clojure
                                 "|(#object[java.time.Instant 0x4aef4247 \"2017-11-13T18:42:13.209Z\"] )"
                                 "i")
                     "|(#object[java.time.Instant 0x4aef4247 \"2017-11-13T18:42:13.209Z\"])"))
    (should (string= (lispy-with clojure
                                 "|(do (.method   object))"
                                 "i")
                     "|(do (.method object))"))))

(defun lispy-test-normalize ()
  (interactive)
  (goto-char (point-min))
  (catch 'break
    (let ((pt (point)))
      (while (not (buffer-modified-p))
        (setq pt (max pt (point)))
        (lispy-down 1)
        (if (< (point) pt)
            (throw 'break nil))
        (lispy-tab)))))

(ert-deftest lispy-ace-subword ()
  (should (string= (lispy-with "|foo-bar-baz~" (lispy-ace-subword 1))
                   "~foo|-bar-baz")))

(ert-deftest lispy-flatten ()
  (should (string= (lispy-with
                    "(defun square (x &optional y &rest z)\n  (if y\n      (cons 200 z)\n    (* x x)))|\n(square 10 1 2 3)"
                    "ej" (lispy-flatten nil))
                   "(defun square (x &optional y &rest z)\n  (if y\n      (cons 200 z)\n    (* x x)))\n(if 1\n    (cons 200 (list 2 3))\n  (* 10 10))|"))
  (should (string= (lispy-with
                    "(defun square (x &optional y &rest z)\n  (if y\n      (cons 200 z)\n    (* x x)))|\n(square 10 1)"
                    "ej" (lispy-flatten nil))
                   "(defun square (x &optional y &rest z)\n  (if y\n      (cons 200 z)\n    (* x x)))\n(if 1\n    (cons 200 (list))\n  (* 10 10))|"))
  (should (string= (lispy-with
                    "(defun square (x &optional y &rest z)\n  (if y\n      (cons 200 z)\n    (* x x)))|\n(square 10)"
                    "ej" (lispy-flatten nil))
                   "(defun square (x &optional y &rest z)\n  (if y\n      (cons 200 z)\n    (* x x)))\n(if nil\n    (cons 200 (list))\n  (* 10 10))|")))

(ert-deftest lispy-mark-list ()
  (should (string= (lispy-with "|;; foo\n(bar)" (lispy-mark-list 1))
                   "~;; foo|\n(bar)"))
  (should (string= (lispy-with "~;; foo|\n(bar)" (lispy-mark-list 1))
                   "|;; foo\n(bar)"))
  (should (string= (lispy-with "~(foo bar)|" (lispy-mark-list 0))
                   "(~foo bar|)"))
  (should (string= (lispy-with "(progn ,@(cdr re)|)" "m")
                   "(progn |,@(cdr re)~)"))
  (should (string= (lispy-with "(progn ,@(cdr re)|)" "mm")
                   "(progn ,@|(cdr re))"))
  (should (string= (lispy-with "(progn ,@|(cdr re))" "m")
                   "(progn ~,@(cdr re)|)"))
  (should (string= (lispy-with "(progn ,@|(cdr re))" "mm")
                   "(progn ,@(cdr re)|)"))
  (should (string= (lispy-with clojure "#|{:bar 'baz}" "0m")
                   "#{&:bar 'baz|}"))
  (should (string= (lispy-with "#2A|((a b) (0 1))" "m")
                   "~#2A((a b) (0 1))|")))

(ert-deftest lispy-mark-car ()
  (should (string= (lispy-with "|\"foo\"~" "i")
                   "\"~foo|\""))
  (should (string= (lispy-with "~'(\n  foo)|" "i")
                   "'(\n  ~foo|)"))
  (should (string= (lispy-with "|'(\n  foo)~" "i")
                   "'(\n  ~foo|)"))
  (should (string= (lispy-with
                    "|(add-to-list 'auto-mode-alist '(\"\\\\.cache\\\\'\" . emacs-lisp-mode))"
                    "mi")
                   "(~add-to-list| 'auto-mode-alist '(\"\\\\.cache\\\\'\" . emacs-lisp-mode))"))
  (should (string= (lispy-with
                    "|(add-to-list 'auto-mode-alist '(\"\\\\.cache\\\\'\" . emacs-lisp-mode))"
                    "miji")
                   "(add-to-list '~auto-mode-alist| '(\"\\\\.cache\\\\'\" . emacs-lisp-mode))"))
  (should (string= (lispy-with "\"See ~`plumage'|.\"" "i")
                   "\"See `~plumage|'.\""))
  (should (string= (lispy-with "(list ~\"one\" \"two\"|)" "i")
                   "(list ~\"one\"| \"two\")")))

(ert-deftest lispy-bind-variable ()
  (should (string= (lispy-with clojure "(+ |(1 2) 3)"
                               (lispy-bind-variable)
                               (insert "three")
                               (lispy-map-done))
                   "(+ (let |[three (1 2)]\n     three) 3)"))
  (should (string= (lispy-with "(+ |(1 2) 3)"
                               (lispy-bind-variable)
                               (insert "three")
                               (lispy-map-done))
                   "(+ (let |((three (1 2)))\n     three) 3)")))

(ert-deftest lispy-unbind-variable ()
  ;; :expected-result :fail
;;   (should (string= (lispy-with "(let ((x 1)\n      |(y 2))\n  (+ x y))"
;;                                (lispy-unbind-variable))
;;                    "(let (|(x 1))\n  (+ x 2))"))
;;   (should (string=
;;            (lispy-flet (recenter (&optional x))
;;              (lispy-with "
;; (defun foobar ()
;;   (let (|(x 10)
;;          (y 20)
;;          (z 30))
;;     (foo1 x y z)
;;     (foo2 x z y)
;;     (foo3 y x z)
;;     (foo4 y z x)
;;     (foo5 z x y)
;;     (foo6 z y x)))"
;;                          (lispy-unbind-variable)))
;;            "
;; (defun foobar ()
;;   (let (|(y 20)
;;         (z 30))
;;     (foo1 10 y z)
;;     (foo2 10 z y)
;;     (foo3 y 10 z)
;;     (foo4 y z 10)
;;     (foo5 z 10 y)
;;     (foo6 z y 10)))"))
;;   (should (string=
;;            (lispy-flet (recenter (&optional x))
;;              (lispy-with "
;; (defun foobar ()
;;   (let (|(x 10)
;;          (y 20)
;;          (z 30))
;;     (foo1 x y z)
;;     (foo2 x z y)
;;     (foo3 y x z)
;;     (foo4 y z x)
;;     (foo5 z x y)
;;     (foo6 z y x)))"
;;                          (lispy-unbind-variable)
;;                          (lispy-unbind-variable)))
;;            "
;; (defun foobar ()
;;   (let (|(z 30))
;;     (foo1 10 20 z)
;;     (foo2 10 z 20)
;;     (foo3 20 10 z)
;;     (foo4 20 z 10)
;;     (foo5 z 10 20)
;;     (foo6 z 20 10)))"))
;;   (should (string=
;;            (lispy-flet (recenter (&optional x))
;;              (lispy-with "
;; (defun foobar ()
;;   (foo)
;;   (let (|(x 10))
;;     (+ x x x))
;;   (bar))"
;;                          (lispy-unbind-variable)))
;;            "
;; (defun foobar ()
;;   (foo)
;;   |(+ 10 10 10)
;;   (bar))"))
;;   (should (string=
;;            (lispy-flet (recenter (&optional x))
;;              (lispy-with clojure "
;; (defn foobar []
;;   (let [&x| 10 y 20 z 30]
;;     (+ 1 x y z)
;;     (+ 2 x z y)
;;     (+ 3 y x z)
;;     (+ 4 y z x)
;;     (+ 5 z x y)
;;     (+ 6 z y x)))"
;;                          (lispy-unbind-variable)))
;;            "
;; (defn foobar []
;;   (let |[y 20 z 30]
;;     (+ 1 10 y z)
;;     (+ 2 10 z y)
;;     (+ 3 y 10 z)
;;     (+ 4 y z 10)
;;     (+ 5 z 10 y)
;;     (+ 6 z y 10)))"))
  )


(ert-deftest lispy-other-space ()
  (should (string= (lispy-with "(foo (bar (baz)|))"
                               "o ")
                   "(foo (bar (baz |)))")))

(ert-deftest lispy-beginning-of-defun ()
  (should (string= (lispy-with "(baz)\n(foo (b|ar))"
                               (lispy-beginning-of-defun))
                   "(baz)\n|(foo (bar))"))
  (should (string= (lispy-with "(baz)\n(foo |(bar))" "A")
                   "(baz)\n|(foo (bar))"))
  ;; (should (string= (lispy-with "(baz)\n(foo |(bar))" "AA")
  ;;                  "(baz)\n(foo |(bar))"))
  (should (string= (lispy-with "(baz)\n(foo (|bar~))" "A")
                   "(baz)\n|(foo (bar))"))
  ;; (should (string= (lispy-with "(baz)\n(foo (|bar~))" "AA")
  ;;                  "(baz)\n(foo (|bar~))"))
  )

(ert-deftest lispy-alt-line ()
  (should (string= (lispy-with "(invent 'wheel|)"
                               (lispy-alt-line))
                   "(invent 'wheel\n        |)"))
  (should (string= (lispy-with "(message |\"hello %s\" name)"
                               (lispy-alt-line))
                   "(message \"hello %s\" name\n         |)"))
  (should (string= (lispy-with "(invent 'wheel|)"
                               (lispy-alt-line 2))
                   "(invent 'wheel)\n|"))
  (should (string= (lispy-with "(invent \"wheel|\")"
                               (lispy-alt-line))
                   "(invent \"wheel\"\n        |)"))
  (should (string= (lispy-with "(progn\n  (take-out the-holy-pin)|\n  (count-to-three))"
                               (lispy-alt-line))
                   "(progn\n  (take-out the-holy-pin)\n  |\n  (count-to-three))"))
  (should (string= (lispy-with "(progn\n  (take-out the-holy-pin)\n  (count-to-three)|)"
                               (lispy-alt-line))
                   "(progn\n  (take-out the-holy-pin)\n  (count-to-three)\n  |)"))
  (should (string= (lispy-with "(progn\n  |(take-out the-holy-pin)\n  (count-to-three))"
                               (lispy-alt-line))
                   "(progn\n  (take-out the-holy-pin)\n  |\n  (count-to-three))"))
  (should (string= (lispy-with "(progn\n  (take-out |the-holy-pin)\n  (count-to-three))"
                               (lispy-alt-line))
                   "(progn\n  (take-out the-holy-pin\n            |)\n  (count-to-three))"))
  (should (string= (lispy-with "(progn\n  (take-out |the-holy-pin)\n  (count-to-three))"
                               (lispy-alt-line 2))
                   "(progn\n  (take-out the-holy-pin)\n  |\n  (count-to-three))"))
  (should (string= (lispy-with ";; foo|"
                               (lispy-alt-line))
                   ";; foo\n|")))

(ert-deftest lispy-outline-add ()
  (should (string= (lispy-with "|;;* Intro" "a")
                   ";;* Intro\n;;* |")))

(ert-deftest lispy-outline-add ()
  (should (string= (lispy-with "(quote ~foo|)" "~")
                   "(quote ~~foo|)"))
  (should (string= (lispy-with "(quote ~~foo|)" "~")
                   "(quote ~foo|)")))

(ert-deftest lispy-space ()
  (should (string= (lispy-with "(|foo" " ")
                   "(| foo"))
  (should (string= (lispy-with "(| foo)" " ")
                   "(|foo)"))
  (should (string= (lispy-with "|(foo bar)" "2 ")
                   "(| foo bar)"))
  (should (string= (lispy-with "(foo bar)|" "2 ")
                   "(foo bar |)"))
  (should (string= (lispy-with "|(foo bar)" "3 ")
                   "(foo bar |)"))
  (should (string= (lispy-with "(foo bar)|" "3 ")
                   "(| foo bar)"))
  (should (string= (lispy-with "(foo (bar)|)" " ")
                   "(foo (bar) |)"))
  (should (string= (lispy-with "(foo (bar)|)" "4 ")
                   "(foo (bar\n      |))"))
  (should (string= (lispy-with "(foo |(bar))" "4 ")
                   "(foo (bar\n      |))"))
  (should (string= (lispy-with "|(progn\n  (foo)\n  )" "4 ")
                   "(progn\n  (foo)\n  |)"))
  (should (string= (lispy-with "(progn\n  (foo)\n  )|" "4 ")
                   "(progn\n  (foo)\n  |)"))
  (should (string= (lispy-with "[|()]" " ")
                   "[| ()]"))
  (should (string= (lispy-with "{|()}" " ")
                   "{| ()}"))
  (should (string= (lispy-with "|(cdr )" "3 ")
                   "(cdr |)"))
  (should (string= (lispy-with "foo\"[|]\"" " ")
                   "foo\"[ |]\""))
  (should (string= (lispy-with clojure "(list \\(|)" " ")
                   "(list \\( |)")))

(ert-deftest lispy-kill-word ()
  (should (string= (lispy-with "|  (require 'cl)" (kbd "M-d"))
                   "  (| 'cl)"))
  (should (string= (lispy-with "|  \"(require 'cl)\"" (kbd "M-d"))
                   "  \"(| 'cl)\""))
  (should (string= (lispy-with "\"(require |'cl)\"" (kbd "M-d"))
                   "\"(require '|)\""))
  (should (string= (lispy-with "\"(require '|)\"" (kbd "M-d"))
                   "\"(require ')\"|"))
  (should (string= (lispy-with "(foo \"|bar\")" (kbd "M-d"))
                   "(foo \"|\")"))
  (should (string= (lispy-with "(foo |\"bar\")" (kbd "M-d"))
                   "(foo \"|\")"))
  (should (string= (lispy-with "\"(require |'cl)\"" (lispy-kill-word -1))
                   "\"(|'cl)\""))
  (should (string= (lispy-with "(defun |test)" (kbd "M-d"))
                   "(defun |)"))
  (should (string= (lispy-with "\"this is a |test\"" (kbd "M-d"))
                   "\"this is a |\"")))

(ert-deftest lispy-backward-kill-word ()
  (should (string= (lispy-with "(require 'cl)|" (kbd "M-DEL"))
                   "(require '|)"))
  (should (string= (lispy-with "(require 'cl)|" (kbd "M-DEL") (kbd "C-y"))
                   "(require 'cl|)"))
  (should (string= (lispy-with "(eval-after-load |)" (kbd "M-DEL"))
                   "(eval-after-|)"))
  (should (string= (lispy-with "(eval-after-load |)"
                               (kbd "M-DEL") (kbd "M-DEL"))
                   "(eval-|)"))
  (should (string= (lispy-with "(eval-after-load |)"
                               (kbd "M-DEL") (kbd "M-DEL") (kbd "C-y"))
                   "(eval-after-load |)"))
  (should (string= (lispy-with "(eval-after-load \"foo\")|" (kbd "M-DEL"))
                   "(eval-after-load \"|\")"))
  (should (string= (lispy-with "(eval-after-load \"|\")" (kbd "M-DEL"))
                   "(eval-after-| \"\")"))
  (should (string= (lispy-with "\"foo bar   \"|" (kbd "M-DEL"))
                   "\"foo |\""))
  (should (string= (lispy-with "\"\\nfoo\"|" (kbd "M-DEL"))
                   "\"|\""))
  (should (string= (lispy-with "\"\\nfoo\"|" (kbd "M-DEL"))
                   "\"|\""))
  (should (string= (lispy-with "\"Five is right| out\"" (kbd "M-DEL"))
                   "\"Five is | out\""))
  (should (string= (lispy-with "\"Five is right| out\""
                               (kbd "M-DEL")
                               (kbd "M-DEL"))
                   "\"Five | out\""))
  (should (string= (lispy-with "(nil nil |:color blue)" (kbd "M-DEL"))
                   "(nil |:color blue)"))
  (should (string= (lispy-with "\"\\n |\"" (kbd "M-DEL"))
                   "\"|\"")))

(ert-deftest lispy-kill-sentence ()
  (should (string= (lispy-with "(progn|\n  (foo)\n  (bar))" (kbd "M-k"))
                   "(progn|)"))
  (should (string= (lispy-with "(message |\"foo bar baz\")" (kbd "M-k"))
                   "(message |)"))
  (should (string= (lispy-with "(progn |(foo bar baz))" (kbd "M-k"))
                   "(progn |)"))
  (should (string= (lispy-with "(message \"Then shalt thou count to three|, no more, no less.
                                         Three shall be the number thou shalt count, and the number of the
                                         counting shall be three.\")" (kbd "M-k"))
                   "(message \"Then shalt thou count to three|\")")))

(ert-deftest lispy-hash ()
  (should (string= (lispy-with clojure "foo|" "#")
                   "foo #|"))
  (should (string= (lispy-with clojure "foo|" "##")
                   "foo#|")))

(ert-deftest lispy-newline-and-indent-plain ()
  (should (string= (lispy-with "(mapc #'|say-ni\n      knights)" (kbd "RET"))
                   "(mapc\n #'|say-ni\n knights)"))
  (should (string= (lispy-with "(mapc #'|say-ni\n      knights)" (kbd "C-j"))
                   "(mapc\n #'|say-ni\n knights)")))

(ert-deftest lispy-knight-down ()
  (should (string= (lispy-with "|(defun foo ()\n  (bar)\n  (baz))"
                               (lispy-knight-down))
                   "(defun foo ()\n  |(bar)\n  (baz))")))

(ert-deftest lispy-knight-up ()
  (should (string= (lispy-with "(defun foo ()\n  |(bar)\n  (baz))"
                               (lispy-knight-up))
                   "|(defun foo ()\n  (bar)\n  (baz))")))

(ert-deftest lispy--setq-expression ()
  (should (equal (lispy-with-v el "(dolist |(s '(1 2 3))\n  (message \"val: %d\" s))"
                   (lispy--setq-expression))
                 '(lispy--dolist-item-expr
                   (quote (s (quote (1 2 3)))))))
  (should (equal (lispy-with-v el "(cond |((string= question \"Where'd you get the coconut?\")\n       (message \"We found them.\")))"
                   (lispy--setq-expression))
                 '(if (string=
                       question
                       "Where'd you get the coconut?")
                   (progn
                     (message "We found them."))
                   lispy--eval-cond-msg)))
  (should (equal (lispy-with-v el "(let |(coconuts-migrate (swallow-type 'african) ridden-on-a-horse))"
                   (lispy--setq-expression))
                 '(setq coconuts-migrate
                   nil
                   ridden-on-a-horse
                   nil)))
  (should (equal (lispy-with-v el "(let (coconuts-migrate |(swallow-type 'african) ridden-on-a-horse))"
                   (lispy--setq-expression))
                 '(setq swallow-type
                   (quote african))))
  (should (equal (lispy-with-v el "(cl-labels (|(greeting ()\n (message \"Halt! Who goes there?\")))\n (greeting))"
                   (lispy--setq-expression))
                 '(defun greeting nil
                   (message
                    "Halt! Who goes there?"))))
  (should (equal (lispy-with-v el "(cond |((pred)))"
                   (lispy--setq-expression))
                 '(or (pred)
                   lispy--eval-cond-msg))))

(ert-deftest lispy-eval-other-window ()
  (unless noninteractive
    (cl-labels ((p (keys)
                   (setq s nil)
                   (setq unread-command-events (listify-key-sequence (kbd keys)))
                   (lispy-eval-other-window)))
      (should (string= (lispy-with-v el "(dolist |(s '(1 2 3))\n  (message \"val: %d\" s))"
                         (p "C-m")) "1"))
      (should (string= (lispy-with-v el "(dolist |(s '(1 2 3))\n  (message \"val: %d\" s))"
                         (p "C-n C-m")) "2"))
      (should (string= (lispy-with-v el "(dolist |(s '(1 2 3))\n  (message \"val: %d\" s))"
                         (p "C-n C-n C-m")) "3"))
      (should (string= (lispy-with-v el "(mapcar |(lambda (s) (* s s)) '(1 2))"
                         (p "C-m")) "1"))
      (should (string= (lispy-with-v el "(mapcar |(lambda (s) (* s s)) '(1 2))"
                         (p "C-n C-m")) "2")))))

(ert-deftest lispy-ace-char ()
  (should (string= (lispy-with "|(cons 'norwegian 'blue)"
                               (execute-kbd-macro (kbd "Qob")))
                   "(cons 'n|orwegian 'blue)")))

(ert-deftest lispy-ace-paren ()
  (should (string= (lispy-with "|(progn (setq type 'norwegian-blue)\n       (setq plumage-type 'lovely))"
                               (execute-kbd-macro (kbd "qb")))
                   "(progn |(setq type 'norwegian-blue)\n       (setq plumage-type 'lovely))"))
  (should (string= (lispy-with "|(progn (setq type 'norwegian-blue)\n       (setq plumage-type 'lovely))"
                               (execute-kbd-macro (kbd "qc")))
                   "(progn (setq type 'norwegian-blue)\n       |(setq plumage-type 'lovely))"))
  (should (string= (lispy-with "(progn (setq type 'norwegian-blue)\n       |(setq plumage-type 'lovely))"
                               (execute-kbd-macro (kbd "qa")))
                   "|(progn (setq type 'norwegian-blue)\n       (setq plumage-type 'lovely))")))

(ert-deftest lispy-ace-symbol ()
  (let ((avy-keys-alist nil))
    (should (string= (lispy-with "|(progn (setq type 'norwegian-blue)\n       (setq plumage-type 'lovely))"
                                 (execute-kbd-macro (kbd "ab")))
                     "(progn (~setq| type 'norwegian-blue)\n       (setq plumage-type 'lovely))"))
    (should (string= (lispy-with "|(progn (setq type 'norwegian-blue)\n       (setq plumage-type 'lovely))"
                                 (execute-kbd-macro (kbd "ac")))
                     "(progn (setq ~type| 'norwegian-blue)\n       (setq plumage-type 'lovely))"))
    (should (string= (lispy-with "(progn (setq type 'norwegian-blue)\n       |(setq plumage-type 'lovely))"
                                 (execute-kbd-macro (kbd "aa")))
                     "(progn (setq type 'norwegian-blue)\n       (~setq| plumage-type 'lovely))"))))

(ert-deftest lispy-ace-subword ()
  (should (string= (lispy-with "|(progn (setq type 'norwegian-blue)\n       (setq plumage-type 'lovely))"
                               (execute-kbd-macro (kbd "-g")))
                   "(progn (setq type 'norwegian-blue)\n       (setq |plumage~-type 'lovely))"))
  (should (string= (lispy-with "|(progn (setq type 'norwegian-blue)\n       (setq plumage-type 'lovely))"
                               (execute-kbd-macro (kbd "-e")))
                   "(progn (setq type 'norwegian-|blue~)\n       (setq plumage-type 'lovely))"))
  ;; should be able to cancel
  (should (string= (lispy-with "|(a b c)"
                               (execute-kbd-macro (kbd "- ESC")))
                   "|(a b c)")))

(ert-deftest lispy-ace-symbol-replace ()
  (should (string= (lispy-with "|(progn (setq type 'norwegian-blue)\n       (setq plumage-type 'lovely))"
                               (execute-kbd-macro (kbd "Hd")))
                   "(progn (setq type |)\n       (setq plumage-type 'lovely))"))
  (should (string= (lispy-with "|(progn (setq type 'norwegian-blue)\n       (setq plumage-type 'lovely))"
                               (execute-kbd-macro (kbd "Hg")))
                   "(progn (setq type 'norwegian-blue)\n       (setq plumage-type |))")))

;;* Parinfer compatibility tests
(ert-deftest lispy-parens-auto-wrap ()
  (lispy-set-key-theme '(parinfer))
  (should (string= (lispy-with "|a" "(")
                   "(| a)"))
  (should (string= (lispy-with "|a" (setq current-prefix-arg '-) "(")
                   "(|) a"))
  (should (string= (lispy-with "(a)| (b)" "(")
                   "(a) (| (b))"))
  ;; test situations where no wrapping occurs
  (should (string= (lispy-with "|" "(")
                   "(|)"))
  (should (string= (lispy-with "a (|) b" "(")
                   "a ((|)) b"))
  (should (string= (lispy-with "`(,|)" "(")
                   "`(,(|))"))
  (should (string= (lispy-with "(a |) b" "(")
                   "(a (|)) b"))
  (should (string= (lispy-with "a|" "(")
                   "a (|)"))
  (should (string= (lispy-with "(a |\n )" "(")
                   "(a (|)\n )"))
  (should (string= (lispy-with "(a)|" "(")
                   "(a) (|)"))
  (should (string= (lispy-with "\"a\"|" "(")
                   "\"a\" (|)"))
  ;; test space-unless behavior
  (should (string= (lispy-with "a|" "(")
                   "a (|)"))
  (should (string= (lispy-with ",@|" "(")
                   ",@(|)"))
  (should (string= (lispy-with clojure "#|" "(")
                   "#(|)"))
  (should (string= (lispy-with clojure "#?@|" "(")
                   "#?@(|)"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-brackets-auto-wrap ()
  (lispy-set-key-theme '(parinfer))
  (should (string= (lispy-with "|a" "[")
                   "[| a]"))
  (should (string= (lispy-with "|a" (setq current-prefix-arg '-) "[")
                   "[|] a"))
  ;; test space-unless behavior
  (should (string= (lispy-with clojure "`|" "[")
                   "`[|]"))
  (should (string= (lispy-with clojure "#my.klass_or_type_or_record|" "[")
                   "#my.klass_or_type_or_record[|]"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-braces-auto-wrap ()
  (lispy-set-key-theme '(parinfer))
  (should (string= (lispy-with "|a" "{")
                   "{| a}"))
  (should (string= (lispy-with "|a" (setq current-prefix-arg '-) "{")
                   "{|} a"))
  ;; test space-unless behavior
  (should (string= (lispy-with clojure "`|" "{")
                   "`{|}"))
  (should (string= (lispy-with clojure "^|" "{")
                   "^{|}"))
  (should (string= (lispy-with clojure "#my.record|" "{")
                   "#my.record{|}"))
  (should (string= (lispy-with clojure "symbol|" "{")
                   "symbol {|}"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-barf-to-point-nostring ()
  (lispy-set-key-theme '(parinfer))
  (should (string= (lispy-with "(a |\"b\" c)" ")")
                   "(a)| \"b\" c"))
  (should (string= (lispy-with "(a \"|b\" c)" ")")
                   "(a \")|b\" c)"))
  (should (string= (lispy-with "(a \"b|\" c)" ")")
                   "(a \"b)|\" c)"))
  (should (string= (lispy-with "(a \"b\"| c)" ")")
                   "(a \"b\")| c"))
  (should (string= (lispy-with ";; |" ")")
                   ";; )|"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-parens-barf-to-point-or-jump-nostring ()
  (should (string= (lispy-with
                    "(a| b)"
                    (lispy-parens-barf-to-point-or-jump-nostring nil))
                   "(a)| b"))
  (should (string= (lispy-with
                    "(a |b)"
                    (lispy-parens-barf-to-point-or-jump-nostring t))
                   "a |(b)"))
  (should (string= (lispy-with
                    "([a |b] c)"
                    (lispy-parens-barf-to-point-or-jump-nostring nil))
                   "([a b] c)|"))
  (should (string= (lispy-with
                    "(a [b |c])"
                    (lispy-parens-barf-to-point-or-jump-nostring t))
                   "|(a [b c])")))

(ert-deftest lispy-brackets-barf-to-point-or-jump-nostring ()
  (should (string= (lispy-with
                    "[a| b]"
                    (lispy-brackets-barf-to-point-or-jump-nostring nil))
                   "[a]| b"))
  (should (string= (lispy-with
                    "[a |b]"
                    (lispy-brackets-barf-to-point-or-jump-nostring t))
                   "a |[b]"))
  (should (string= (lispy-with
                    "[(a |b) c]"
                    (lispy-brackets-barf-to-point-or-jump-nostring nil))
                   "[(a b) c]|"))
  (should (string= (lispy-with
                    "[a (b |c)]"
                    (lispy-brackets-barf-to-point-or-jump-nostring t))
                   "|[a (b c)]")))

(ert-deftest lispy-braces-barf-to-point-or-jump-nostring ()
  (should (string= (lispy-with clojure
                    "{a| b}"
                    (lispy-braces-barf-to-point-or-jump-nostring nil))
                   "{a}| b"))
  (should (string= (lispy-with clojure
                    "{a |b}"
                    (lispy-braces-barf-to-point-or-jump-nostring t))
                   "a |{b}"))
  (should (string= (lispy-with clojure
                    "{(a |b) c}"
                    (lispy-braces-barf-to-point-or-jump-nostring nil))
                   "{(a b) c}|"))
  (should (string= (lispy-with clojure
                    "{a (b |c)}"
                    (lispy-braces-barf-to-point-or-jump-nostring t))
                   "|{a (b c)}")))

(ert-deftest lispy-delete-backward-or-splice-or-slurp ()
  (lispy-set-key-theme '(parinfer))
  (should (string= (lispy-with "(|a b c)" (kbd "DEL"))
                   "|a b c"))
  (should (string= (lispy-with "(|(a b c))" (kbd "DEL"))
                   "|(a b c)"))
  (should (string= (lispy-with "(a |b c)" (kbd "DEL") (kbd "DEL"))
                   "(|b c)"))
  (should (string= (lispy-with "((a b)| c)" (kbd "DEL"))
                   "((a b| c))"))
  (should (string= (lispy-with "(a)| (b)" (kbd "DEL"))
                   "(a| (b))"))
  (should (string= (lispy-with "(((a)))|" (kbd "DEL") (kbd "DEL") (kbd "DEL"))
                   "(((a|)))"))
  (should (string= (lispy-with ";; (a (b)| c)"
                               (setq current-prefix-arg 4)
                               (kbd "DEL"))
                   ";; (a| c)"))
  (should (string= (lispy-with "\"(a (b)| c)\""
                               (setq current-prefix-arg 4)
                               (kbd "DEL"))
                   "\"(a| c)\""))
  ;; keep newline
  (should (string= (lispy-with "(foo\n (|))" (kbd "DEL"))
                   "(foo\n |)"))
  ;; behavior at string boundaries
  (should (string= (lispy-with "\"a b c\"|" (kbd "DEL"))
                   "\"a b c|\""))
  (should (string= (lispy-with "\"|a b c\"" (kbd "DEL"))
                   "|"))
  ;; space cleanup
  (should (string= (lispy-with "(foo (| (bar) baz))" (kbd "DEL"))
                   "(foo |(bar) baz)"))
  ;; test that quotes also get deleted
  (should (string= (lispy-with "'(|)" (kbd "DEL"))
                   "|"))
  (should (string= (lispy-with "(,@(|))" (kbd "DEL"))
                   "(|)"))
  (should (string= (lispy-with "#2A(|(a b) (0 1))" (kbd "DEL"))
                   "|(a b) (0 1)"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-delete-or-splice-or-slurp ()
  (lispy-set-key-theme '(parinfer))
  (should (string= (lispy-with "|(a b c)" (kbd "C-d"))
                   "|a b c"))
  (should (string= (lispy-with "(|(a b c))" (kbd "C-d"))
                   "(|a b c)"))
  (should (string= (lispy-with "(a |b c)" (kbd "C-d") (kbd "C-d"))
                   "(a |c)"))
  (should (string= (lispy-with "((a b|) c)" (kbd "C-d"))
                   "((a b| c))"))
  (should (string= (lispy-with "(a|) (b)" (kbd "C-d"))
                   "(a| (b))"))
  (should (string= (lispy-with "(((a|)))" (kbd "C-d") (kbd "C-d") (kbd "C-d"))
                   "(((a)))|"))
  (should (string= (lispy-with ";; (a |(b) c)"
                               (setq current-prefix-arg 4)
                               (kbd "C-d"))
                   ";; (a |c)"))
  (should (string= (lispy-with "\"(a |(b) c)\""
                               (setq current-prefix-arg 4)
                               (kbd "C-d"))
                   "\"(a |c)\""))
  ;; keep newline
  (should (string= (lispy-with "(foo\n |())" (kbd "C-d"))
                   "(foo\n |)"))
  ;; behavior at string boundaries
  (should (string= (lispy-with "\"a b c|\"" (kbd "C-d"))
                   "\"a b c\"|"))
  (should (string= (lispy-with "|\"a b c\"" (kbd "C-d"))
                   "|"))
  ;; test that quotes also get deleted
  (should (string= (lispy-with "'|()" (kbd "C-d"))
                   "|"))
  (should (string= (lispy-with "(,@|())" (kbd "C-d"))
                   "(|)"))
  (should (string= (lispy-with "#2A|((a b) (0 1))" (kbd "C-d"))
                   "|(a b) (0 1)"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

;;* Paredit compatibility tests
(ert-deftest lispy-paredit-open-round ()
  (should (string= (lispy-with "(a b |c d)"
                               "(")
                   "(a b (|) c d)"))
  (should (string= (lispy-with "(foo \"bar |baz\" quux)"
                               (execute-kbd-macro "("))
                   "(foo \"bar (|baz\" quux)")))

(ert-deftest lispy-paredit-close-round ()
  (should (string= (lispy-with "(a b |c   )"
                               ")")
                   "(a b c)|"))
  (should (string= (lispy-with "; Hello,| world!"
                               ")")
                   "; Hello,)| world!")))

(ert-deftest lispy-paredit-close-round-and-newline ()
  (lispy-set-key-theme '(paredit))
  (should (string= (lispy-with "(defun f (x|  ))"
                               (kbd "M-)"))
                   "(defun f (x)\n  |)"))
  (should (string= (lispy-with "; (Foo.|"
                               (kbd "M-)"))
                   "; (Foo.)|"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-open-square ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(a b |c d)"
                               "[")
                   "(a b [|] c d)"))
  (should (string= (lispy-with "(foo \"bar |baz\" quux)"
                               "[")
                   "(foo \"bar [|baz\" quux)"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-close-square ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(define-key keymap [frob|  ] 'frobnicate)"
                               "]")
                   "(define-key keymap [frob]| 'frobnicate)"))
  (should (string= (lispy-with "; [Bar.|"
                               "]")
                   "; [Bar.]|"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-doublequote ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(frob grovel |full lexical)"
                               "\"")
                   "(frob grovel \"|\" full lexical)"))
  (should (string= (lispy-with "(frob grovel \"|\" full lexical)"
                               "\"")
                   "(frob grovel \"\"| full lexical)"))
  (should (string= (lispy-with "(foo \"bar |baz\" quux)"
                               "\"")
                   "(foo \"bar \\\"|baz\" quux)"))
  (should (string= (lispy-with "(frob grovel)   ; full |lexical"
                               "\"")
                   "(frob grovel)   ; full \"|lexical"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-meta-doublequote ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(foo \"bar |baz\" quux)"
                               (kbd "M-\""))
                   "(foo \"bar baz\"| quux)"))
  (should (string= (lispy-with "(foo |(bar #\\x \"baz \\\\ quux\") zot)"
                               (kbd "M-\""))
                   "(foo \"|(bar #\\\\x \\\"baz \\\\\\\\ quux\\\")\" zot)"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-newline ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(let ((n (frobbotz))) |(display (+ n 1)\nport))"
                               (kbd "C-j"))
                   "(let ((n (frobbotz)))\n  |(display (+ n 1)\n           port))"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-forward-delete ()
  (should (string= (lispy-with "(quu|x \"zot\")" (lispy-forward-delete 1))
                   "(quu| \"zot\")"))
  (should (string= (lispy-with "(foo (|) bar)" (lispy-forward-delete 1))
                   "(foo | bar)"))
  (should (string= (lispy-with "|(foo bar)" (lispy-forward-delete 1))
                   "(|foo bar)"))
  (should (string= (lispy-with "(quux |\"zot\")" (lispy-forward-delete 1))
                   "(quux \"|zot\")"))
  (should (string= (lispy-with "(quux \"|zot\")" (lispy-forward-delete 1))
                   "(quux \"|ot\")"))
  (should (string= (lispy-with "(foo (|))" (lispy-forward-delete 1))
                   "(foo |)"))
  (should (string= (lispy-with "\"|\"" (lispy-forward-delete 1))
                   "|"))
  (should (string= (lispy-with "(baz \"foobar|\")" (lispy-forward-delete 1))
                   "(baz |\"foobar\")"))
  (should (string= (lispy-with "(foo (bar|))" (lispy-forward-delete 1))
                   "(foo |)")))

(ert-deftest lispy-paredit-backward-delete ()
  (should (string= (lispy-with "(\"zot\" q|uux)" (lispy-backward-delete 1))
                   "(\"zot\" |uux)"))
  (should (string= (lispy-with "(\"zot\"| quux)" (lispy-backward-delete 1))
                   "(\"zot|\" quux)"))
  (should (string= (lispy-with "(\"zot|\" quux)" (lispy-backward-delete 1))
                   "(\"zo|\" quux)"))
  (should (string= (lispy-with "(foo (|) bar)" (lispy-backward-delete 1))
                   "(foo | bar)"))
  (should (string= (lispy-with "(foo bar)|" (lispy-backward-delete 1))
                   "(foo bar|)"))
  (should (string= (lispy-with "(|)" (lispy-backward-delete 1))
                   "|"))
  (should (string= (lispy-with "(foo (|))" (lispy-backward-delete 1))
                   "(foo |)"))
  (should (string= (lispy-with "\"|\"" (lispy-backward-delete 1))
                   "|"))
  (should (string= (lispy-with "(baz \"|foobar\")" (lispy-backward-delete 1))
                   "(baz \"foobar\"|)"))
  (should (string= (lispy-with "(foo (|bar))" (lispy-backward-delete 1))
                   "(foo |)")))

(ert-deftest lispy-paredit-kill ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(foo bar)|     ; Useless comment!"
                               (kbd "C-k"))
                   "(foo bar)|"))
  (should (string= (lispy-with "(|foo bar)     ; Useful comment!"
                               (kbd "C-k"))
                   "(|)     ; Useful comment!"))
  (should (string= (lispy-with "|(foo bar)     ; Useless line!"
                               (kbd "C-k"))
                   "|"))
  (should (string= (lispy-with "(foo \"|bar baz\"\n     quux)"
                               (kbd "C-k"))
                   "(foo \"|\"\n     quux)"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-forward-kill-word ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "|(foo bar)    ; baz"
                               (kbd "M-d"))
                   "(| bar)    ; baz"))
  (should (string= (lispy-with "(| bar)    ; baz"
                               (kbd "M-d"))
                   "(|)    ; baz"))
  (should (string= (lispy-with "(|)    ; baz"
                               (kbd "M-d"))
                   "()    ;|"))
  (should (string= (lispy-with ";;;| Frobnicate\n(defun frobnicate ...)"
                               (kbd "M-d"))
                   ";;;|\n(defun frobnicate ...)"))
  (should (string= (lispy-with ";;;|\n(defun frobnicate ...)"
                               (kbd "M-d"))
                   ";;;\n(| frobnicate ...)"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-backward-kill-word ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(foo bar)    ; baz\n(quux)|"
                               (kbd "M-DEL"))
                   "(foo bar)    ; baz\n(|)"))
  (should (string= (lispy-with "(foo bar)    ; baz\n(|)"
                               (kbd "M-DEL"))
                   "(foo bar)    ; |\n()"))
  (should (string= (lispy-with "(foo bar)    ; |\n()"
                               (kbd "M-DEL"))
                   "(foo |)    ;\n()"))
  (should (string= (lispy-with "(foo |)    ; \n()"
                               (kbd "M-DEL"))
                   "(|)    ; \n()"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-forward ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(foo |(bar baz) quux)"
                               (kbd "C-M-f"))
                   "(foo (bar baz)| quux)"))
  (should (string= (lispy-with "(foo (bar)|)"
                               (kbd "C-M-f"))
                   "(foo (bar))|"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-backward ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(foo (bar baz)| quux)"
                               (kbd "C-M-b"))
                   "(foo |(bar baz) quux)"))
  (should (string= (lispy-with "(|(foo) bar)"
                               (kbd "C-M-b"))
                   "|((foo) bar)"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-wrap-round ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(foo |bar baz)"
                               (kbd "M-("))
                   "(foo (| bar) baz)"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-splice-sexp ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(foo (bar| baz) quux)"
                               (kbd "M-s"))
                   "(foo bar| baz quux)"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-splice-sexp-killing-backward ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(foo (let ((x 5)) |(sqrt n)) bar)"
                               (kbd "M-<up>"))
                   "(foo |(sqrt n) bar)"))
  (should (string= (lispy-with "(progn (1) |(2) (3))"
                               (kbd "M-<up>"))
                   "|(2) (3)"))
  (should (string= (lispy-with "(a (b c |d e) f)"
                               (kbd "M-<up>"))
                   "(a d e| f)"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-splice-sexp-killing-forward ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(a (b c| d e) f)"
                               (kbd "M-<down>"))
                   "(a b c| f)"))
  (should (string= (lispy-with "((a) (b) (c)| (d) (f))"
                               (kbd "M-<down>"))
                   "(a) (b) (c)|"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-raise-sexp ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(dynamic-wind in (lambda () |body) out)"
                               (kbd "M-r"))
                   "(dynamic-wind in |body out)"))
  (should (string= (lispy-with "(dynamic-wind in |body out)"
                               (kbd "M-r"))
                   "|body"))
  (should (string= (lispy-with "(foo bar\n     (baz 1 2 3\n          (+ 2 3)|))"
                               (kbd "M-r"))
                   "(foo bar\n     (+ 2 3)|)"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-convolute-sexp ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(let ((x 5) (y 3)) (frob |(zwonk)) (wibblethwop))"
                               (kbd "M-?"))
                   "(frob |(let ((x 5) (y 3)) (zwonk) (wibblethwop)))"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-forward-slurp-sexp ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(foo (bar |baz) quux zot)"
                               (kbd "C-<right>"))
                   "(foo (bar |baz quux) zot)"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-forward-barf-sexp ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(foo (bar |baz quux) zot)"
                               (kbd "C-<left>"))
                   "(foo (bar |baz) quux zot)"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-backward-slurp-sexp ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(foo bar (baz| quux) zot)"
                               (kbd "C-M-<left>"))
                   "(foo (bar baz| quux) zot)"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-backward-barf-sexp ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(foo (bar baz |quux) zot)"
                               (kbd "C-M-<right>"))
                   "(foo bar (baz |quux) zot)"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-split-sexp ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(hello| world)"
                               (kbd "M-S"))
                   "(hello)\n|( world)"))
  (should (string= (lispy-with "\"Hello, |world!\""
                               (kbd "M-S"))
                   "\"Hello, \"\n|\"world!\""))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-join-sexps ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "(hello)| (world)"
                               (kbd "M-J"))
                   "(hello world)|"))
  (should (string= (lispy-with "\"Hello, \"\n|\"world!\""
                               (kbd "M-J"))
                   "\"Hello, |world!\""))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paredit-semicolon ()
  (lispy-set-key-theme '(special paredit))
  (should (string= (lispy-with "|(frob grovel)"
                               ";")
                   "|;; (frob grovel)"))
  (should (string= (lispy-with "(frob |grovel)"
                               ";")
                   "|(frob ;; grovel\n )"))
  (should (string= (lispy-with "(frob |grovel (bloit\n               zargh))"
                               ";")
                   "|(frob ;; grovel (bloit\n      ;;         zargh)\n )"))
  (should (string= (lispy-with "(frob grovel)          |"
                               ";")
                   "(frob grovel)                           ;|"))
  (lispy-set-key-theme '(special lispy c-digits oleh)))

(ert-deftest lispy-paste ()
  (should (string= (lispy-with "|(a witch)"
                               "n2P")
                   "(a (a witch)| witch)"))
  (should (string= (lispy-with "|(a witch)"
                               "n3P")
                   "(a witch (a witch)|)"))
  (should (string= (lispy-with "(progn\n  |(one)\n  (two)\n  (three))"
                               "njP")
                   "(progn\n  (one)\n  (one)|\n  (two)\n  (three))"))
  (should (string= (lispy-with "(progn\n  |(one)\n  (two)\n  (three))"
                               "njjP")
                   "(progn\n  (one)\n  (two)\n  (one)|\n  (three))"))
  (should (string= (lispy-with "(progn\n  (one)|\n  (two)\n  (three))"
                               "njP")
                   "(progn\n  (one)\n  (two)\n  (one)|\n  (three))"))
  (should (string= (lispy-with "(progn\n  (one)|\n  (two)\n  (three))"
                               "njjP")
                   "(progn\n  (one)\n  (two)\n  (three)\n  (one)|)")))

(ert-deftest lispy--balance ()
  (should (string= (lispy--balance "(a")
                   "(a)"))
  (should (string= (lispy--balance "a)")
                   "(a)"))
  (should (string= (lispy--balance "a)(b")
                   "(a)(b)"))
  (should (string= (lispy--balance "({[a b] c")
                   "({[a b] c})"))
  (should (string= (lispy--balance "a [b c]})")
                   "({a [b c]})"))
  (should (string= (lispy--balance "a)]}({[b")
                   "{[(a)]}({[b]})")))

(ert-deftest lispy-reverse ()
  (should (string= (lispy-with "|(read-string slurp clojure.java.io/resource path)"
                               (execute-kbd-macro "xR"))
                   "|(path clojure.java.io/resource slurp read-string)"))
  (should (string= (lispy-with "(read-string slurp clojure.java.io/resource path)|"
                               (execute-kbd-macro "xR"))
                   "(path clojure.java.io/resource slurp read-string)|"))
  (should (string= (lispy-with "(read-string ~slurp clojure.java.io/resource path|)"
                               (execute-kbd-macro "xR"))
                   "(read-string ~path clojure.java.io/resource slurp|)"))
  (should (string= (lispy-with "(read-string |slurp clojure.java.io/resource path~)"
                               (execute-kbd-macro "xR"))
                   "(read-string |path clojure.java.io/resource slurp~)"))
  (should (string= (lispy-with "(defn read-resource\n  \"Read a resource into a string.\"\n  [path]\n  |(read-string\n   (slurp\n    (clojure.java.io/resource path))))"
                               (execute-kbd-macro "f//xR2 ->[i"))
                   "(defn read-resource\n  \"Read a resource into a string.\"\n  [path]\n  |(-> path clojure.java.io/resource\n      slurp\n      read-string))")))

(ert-deftest lispy-repeat ()
  (should (string= (lispy-with "(message \"a witch\")|"
                               "2c..")
                   "(message \"a witch\")\n(message \"a witch\")\n(message \"a witch\")\n(message \"a witch\")\n(message \"a witch\")|")))

(ert-deftest lispy-interleave ()
  (should (equal (lispy-interleave 0 '(1 2 3))
                 '(1 0 2 0 3)))
  (should (equal (lispy-interleave 1 '(1 2 3))
                 '(1 2 1 3)))
  (should (equal (lispy-interleave 2 '(1 2 3))
                 '(1 2 3)))
  (should (equal (lispy-interleave 3 '(1 2 3))
                 '(1 3 2 3)))
  (should (equal (lispy-interleave 0 '(1 2 3 4 5 6 7 8 9 10) 2)
                 '(1 2 0 3 4 0 5 6 0 7 8 0 9 10)))
  (should (equal (lispy-interleave 0 '(1 2 3 4 5 6 7 8 9 10) 3)
                 '(1 2 3 0 4 5 6 0 7 8 9 0 10)))
  (should (equal (lispy-interleave 3 '(1 2 3 4 5 6 7 8 9 10) 3)
                 '(1 2 3 4 5 6 3 7 8 9 3 10))))

(ert-deftest lispy-extract-block ()
  (should (string= (lispy-with "(defun cube (x)\n  (* x |(* x x)))"
                               (execute-kbd-macro "xdsquare x["))
                   "(defun square (x)\n  (* x x))\n\n(defun cube (x)\n  (* x |(square x)))"))
  (should (string= (lispy-with clojure "(defn cube [x]\n  (* x |(* x x)))"
                                       (execute-kbd-macro "xdsquare x["))
                   "(defn square [x]\n  (* x x))\n\n(defn cube [x]\n  (* x |(square x)))")))

(ert-deftest lispy-extract-defun ()
  (should (string= (lispy-with "(defun foo (x)\n  |(let ((y (* x x))\n        (z (+ x x)))\n    (list y z y z)))"
                               (execute-kbd-macro "xdhelper"))
                   "(defun helper (y z)\n  (list y z y z))\n\n(defun foo (x)\n  (helper (* x x) (+ x x))|)")))


(ert-deftest lispy-debug-step-in ()
  (should (equal (lispy-with-v el
                     "|(mapcar\n (lambda (x))\n (mapcar\n  (lambda (y) (expt y 3))\n  (number-sequence 10 42)))"
                   (setq x "42")
                   (lispy-debug-step-in)
                   x)
                 1000)))

(ert-deftest lispy--pretty-args ()
  (should (equal (lispy--pretty-args 'dotimes)
                 #("(dotimes (var count [result]) body...)"
                   1 8 (face lispy-face-hint)
                   9 29 (face lispy-face-req-nosel)
                   30 37 (face lispy-face-rst-nosel))))
  (should (equal (lispy--pretty-args 'defun)
                 #("(defun name arglist docstring decl body...)"
                   1 6 (face lispy-face-hint)
                   7 11 (face lispy-face-req-nosel)
                   12 19 (face lispy-face-req-nosel)
                   20 29 (face lispy-face-opt-nosel)
                   30 34 (face lispy-face-opt-nosel)
                   35 42 (face lispy-face-rst-nosel))))
  (should (equal (lispy--pretty-args 'defvar)
                 #("(defvar symbol initvalue docstring)"
                   1 7 (face lispy-face-hint)
                   8 14 (face lispy-face-req-nosel)
                   15 24 (face lispy-face-opt-nosel)
                   25 34 (face lispy-face-opt-nosel)))))

(ert-deftest lispy-eval-python-str ()
  (require 'le-python)
  (should (equal (lispy-with-v py
                     "\nif cond1:\n   |if cond2:\n        expr1\n        if cond3:\n            expr2\n        else:\n            expr3\n    else:\n        expr4\nelse:\n    expr5"
                   (lispy-eval-python-str))
                 "if cond2:\n     expr1\n     if cond3:\n         expr2\n     else:\n         expr3\n else:\n     expr4"))
  (should (equal (lispy-with-v py
                     "|@up_down\ndef greet(name):\n    return \"my oh my, {}\".format(name)\n\ndef other():\n    pass"
                   (let ((forward-sexp-function nil))
                     (lispy-eval-python-str)))
                 "@up_down\ndef greet(name):\n    return \"my oh my, {}\".format(name)"))
  (unless (version< emacs-version "24.4.1")
    (should (equal (progn
                     ;; skip initialization msg
                     (lispy--eval-python-plain "")
                     (sit-for 0.1)
                     (lispy--eval-python "print(\"one\")\nprint(\"two\")\nx = 2 + 1"))
                   "x = 3"))))

(ert-deftest lispy-python-symbol-bnd ()
  (should (equal (lispy-with-v py "def test_detector ():\n    detector.getChannelCount ().|"
                   (lispy--string-dwim
                    (lispy-python-symbol-bnd)))
                 "detector.getChannelCount ()."))
  (should (equal (lispy-with-v py "def test_detector ():\n    detector.getDetectorProperties ().getOwner ().|"
                   (lispy--string-dwim
                    (lispy-python-symbol-bnd)))
                 "detector.getDetectorProperties ().getOwner ()."))
  (should (equal (lispy-with-v py "foo().bboxes[0].|"
                   (lispy--string-dwim
                    (lispy-python-symbol-bnd)))
                 "foo().bboxes[0].")))

(ert-deftest lispy-eval-str-racket ()
  ;; (let ((geiser-active-implementations '(racket)))
  ;;   (should (equal (lispy-with-v scm
  ;;                      "(list #hash|((1 . 2) (3 . 4)))"
  ;;                    (lispy--string-dwim))
  ;;                  "#hash((1 . 2) (3 . 4))"))
  ;;   (should (equal (lispy-with-v scm
  ;;                      "(list #hash((1 . 2) (3 . 4))| foo)"
  ;;                    (lispy--string-dwim))
  ;;                  "#hash((1 . 2) (3 . 4))")))
  )

(ert-deftest lispy--insert-eval-result ()
  (should (string=
           (lispy-with-v py
               "|"
             (lispy--insert-eval-result
              "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]")
             (buffer-string))
           "# =>\n# [0,\n#  1,\n#  2,\n#  3,\n#  4,\n#  5,\n#  6,\n#  7,\n#  8,\n#  9,\n#  10,\n#  11,\n#  12,\n#  13,\n#  14,\n#  15,\n#  16,\n#  17,\n#  18,\n#  19,\n#  20,\n#  21,\n#  22,\n#  23,\n#  24,\n#  25,\n#  26,\n#  27,\n#  28,\n#  29]"))
  (should (string=
           (lispy-with-v py
               "|"
             (lispy--insert-eval-result
              "{0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, 11: 11, 12: 12, 13: 13, 14: 14, 15: 15, 16: 16, 17: 17, 18: 18, 19: 19}")
             (buffer-string))
           "# =>\n# {0: 0,\n#  1: 1,\n#  2: 2,\n#  3: 3,\n#  4: 4,\n#  5: 5,\n#  6: 6,\n#  7: 7,\n#  8: 8,\n#  9: 9,\n#  10: 10,\n#  11: 11,\n#  12: 12,\n#  13: 13,\n#  14: 14,\n#  15: 15,\n#  16: 16,\n#  17: 17,\n#  18: 18,\n#  19: 19}")))

(ert-deftest lispy--python-eval-string-dwim ()
  ;; (should (string= (lispy--python-eval-string-dwim "x in d2.values()")
  ;;                  "x = list (d2.values())[0]\nprint ((x))"))
  (should (string= (lispy--python-eval-string-dwim "sum(int(x) for x in d2.values())")
                   "sum(int(x) for x in d2.values())"))
  (should (string= (lispy--python-eval-string-dwim "sum(int(x) for x in d2.values())")
                   "sum(int(x) for x in d2.values())"))
  ;; (should (string= (lispy--python-eval-string-dwim "(x, i) in enumerate(lvl_npoints)")
  ;;                  "(x, i) = list (enumerate(lvl_npoints))[0]\nprint (((x, i)))"))
  (should (string= (lispy--python-eval-string-dwim "asdf_123")
                   "print(repr((asdf_123)))"))
  (should (string= (let ((this-command 'lispy-eval))
                     (lispy--python-eval-string-dwim "asdf_123"))
                   "lp.pprint((asdf_123))"))
  (should (string= (let ((this-command 'lispy-eval))
                     (lispy--python-eval-string-dwim "x[\"foo\"] = 2 + 2"))
                   "x[\"foo\"] = 2 + 2\nlp.pprint((x[\"foo\"]))")))

(ert-deftest lispy-extended-eval-str ()
  ;; (should (string=
  ;;          (lispy-with-v py
  ;;              "|x = (\n    \"abc\" +\n    \"def\" +\n    \"foo\" + \"bar\")"
  ;;            (lispy-extended-eval-str
  ;;             (cons (line-beginning-position) (line-end-position))))
  ;;          "x = ( \"abc\" + \"def\" + \"foo\" + \"bar\")"))
  (should (string=
           (lispy-with-v py
               "|print(\"((\", end=\"\")\nprint(\" \".join(['\"' + arg + '\"' for arg in arg_info.args]))"
             (lispy-extended-eval-str
              (cons (line-beginning-position) (line-end-position))))
           "print(\"((\", end=\"\")")))

(ert-deftest lispy--clojure-dot-object ()
  (should (string= (lispy-with-v clj "(. (java.util.Date.) |)"
                     (lispy--clojure-dot-object))
                   "(java.util.Date.)"))
  (should (string= (lispy-with-v clj "(.. (java.util.Date.) to|)"
                     (lispy--clojure-dot-object))
                   "(java.util.Date.)"))
  (should (string= (lispy-with-v clj "(. (java.util.Date.) to|)"
                     (lispy--clojure-dot-object))
                   "(java.util.Date.)"))
  (should (string= (lispy-with-v clj "(.. (java.util.Date.) toString (ends|))"
                     (lispy--clojure-dot-object))
                   "(.. (java.util.Date.) toString )"))
  (should (string= (lispy-with-v clj "(.. (java.util.Date.) toString le|)"
                     (lispy--clojure-dot-object))
                   "(.. (java.util.Date.) toString)"))
  (should (string= (lispy-with-v clj "(. (. (java.util.Date.) (toString)) (sp|))"
                     (lispy--clojure-dot-object))
                   "(. (java.util.Date.) (toString))"))
  (should (string= (lispy-with-v clj "(. (. (. (java.util.Date.) (toString)) (split \"-\")) |)"
                     (lispy--clojure-dot-object))
                   "(. (. (java.util.Date.) (toString)) (split \"-\"))"))
  (should (string= (lispy-with-v clj "(. (. (. (java.util.Date.) (toString)) (split \"-\")) (|))"
                     (lispy--clojure-dot-object))
                   "(. (. (java.util.Date.) (toString)) (split \"-\"))")))

(provide 'lispy-test)

;;; lispy-test.el ends here
